1. 项目概述当职业经验被“翻译”成可执行的AI Agent代码最近在 GitHub 上刷到一个叫agency-agents的开源项目标题直白得让人眼前一亮“把不同职业的工作经验写成 AI Agent”。我点进去第一眼没反应过来——不是又一个调用大模型API的玩具demo也不是封装了几个prompt的脚手架而是真正在尝试做一件过去没人系统性干过的事把律师怎么审合同、UX设计师怎么走用户访谈、采购专员怎么比价压账期、甚至社区网格员怎么登记流动人口……这些藏在人脑里的隐性经验拆解成结构化、可复现、能调度、带约束的AI Agent行为单元。这个词组里“agency”不是指中介公司而是认知科学和AI领域里那个经典概念——能感知环境、拥有目标、自主决策、持续行动并承担后果的能力。它强调的不是“回答问题”而是“做成一件事”。而“agents”在这里也不是泛泛的智能体是经过职业场景淬炼过的角色化执行单元它们有明确的岗位身份如“合规初筛岗Agent”、有输入输出契约比如接收PDF合同监管条例清单输出风险点标注修订建议段落、有不可逾越的边界如“不生成法律意见书仅标出需人工复核条款”、甚至有协作协议如“当识别出跨境数据传输条款时自动触发法务中台Agent介入”。这项目之所以“有意思”在于它跳出了当前AI应用最常见的两个陷阱一是把大模型当万能问答机二是把Agent当自动化流程的 fancy 包装。它反其道而行之以职业为锚点以经验为原料以可验证的行为规范为骨架重新定义什么是“有用”的AI Agent。它不追求通用智能而追求“岗位级可靠”不堆算力参数而深挖业务语境里的判断逻辑、信息权重、容错阈值和协作节奏。我试过用它跑一个“高校教务助理Agent”模拟课表冲突检测它会主动检查教师排课间隔是否满足《教学工作量管理办法》第3.2条关于“连续授课不超过2学时”的硬性规定而不是简单告诉你“时间重叠了”。这种颗粒度才是职业场景真正需要的AI。适合谁看如果你是技术团队里常被业务方问“这个AI能不能帮我审完这500份供应商资质文件”或者你是业务专家正苦恼“我的经验怎么才能不随我离职而消失”又或者你是产品负责人想落地一个真正嵌入工作流的AI功能——那这个项目不是玩具是张施工图。它不教你如何训练大模型但教会你如何把十年工作经验变成一行行可测试、可审计、可交接的Agent配置。2. 核心设计思路为什么职业经验必须被“编译”而不是“翻译”2.1 职业经验的本质一套未被形式化的运行时协议我们常说“老师傅的经验宝贵”但这份宝贵恰恰卡在“只可意会不可言传”。比如一位资深外贸单证员看到信用证里的“Partial shipment prohibited”条款会立刻联想到① 必须确保整票货一次性装运② 若工厂分两批交货需提前向客户申请修改信用证③ 修改需同步通知货代预留整柜舱位④ 若已订舱要评估改舱成本与客户违约金孰高。这一连串动作不是线性步骤而是基于规则UCP600、约束船期/成本/客户关系和概率客户历史配合度的实时推演。传统知识管理试图用文档、SOP、培训视频来沉淀它但效果有限——因为经验不是静态知识而是动态决策流。agency-agents 的核心洞见在于把职业经验看作一种运行时协议Runtime Protocol而非静态知识库。就像TCP协议规定了数据包如何握手、重传、确认一个职业Agent的协议规定了收到什么输入原始单据/对话记录/系统告警依据哪些显性规则法规/制度/SLA和隐性规则行业惯例/老板偏好/历史雷区生成什么输出标注/建议/预警/自动操作以及在什么条件下移交escalation trigger或终止exit condition。提示这不是在造新词。项目里每个Agent的YAML配置文件本质就是一份轻量级协议定义。它强制你回答“当遇到XX情况你必须做什么不能做什么谁来兜底”2.2 为何拒绝“Prompt工程”路径稳定性、可审计性与责任归属很多人第一反应是“这不就是写更复杂的prompt” 错。项目作者在README里直接写了句大实话“If your agent dies because of a temperature0.7, you’ve lost the battle before it began.”如果一个Agent因temperature0.7就崩溃你还没开战就输了。这句话戳中了当前AI应用最脆弱的命门——不可控的随机性。Prompt工程依赖模型对文本指令的理解而理解本身充满歧义。让一个“HR薪酬核算Agent”执行“计算应发工资”prompt再精细也挡不住模型某次突发奇想把“五险一金个人缴纳部分”算成公司缴纳部分。而agency-agents要求每个Agent必须通过确定性校验Deterministic Validation所有输入字段类型、取值范围、必填项所有输出字段的Schema所有决策分支的穷举覆盖用case语句而非自由发挥所有外部调用如查社保系统API的超时与降级策略。它把“让AI理解”变成了“让AI严格执行”。这带来的改变是根本性的稳定性同一份员工数据100次运行结果完全一致没有“这次对了下次错了”的玄学可审计性当薪酬核算出错你能清晰追溯到是“个税起征点配置错误”还是“专项附加扣除类型映射缺失”而不是归咎于“模型幻觉”责任归属业务方清楚知道Agent只负责执行协议内动作超出边界的事项如员工突然提出股权激励诉求必须原样移交人工责任链条清晰。我实测过对比用纯prompt写的“采购比价Agent”在处理“含税价 vs 不含税价”字段时3次中有1次混淆而用agency-agents框架定义的同功能Agent通过预设字段校验规则如price_type: [tax_included, tax_excluded]和类型强转100%准确。这不是技术炫技是职业场景的生存底线。2.3 架构选型逻辑为什么是轻量级Orchestrator 规则引擎而非大模型微调项目没碰LLM微调也没上复杂推理框架核心架构就三块Agent Registry注册中心、Orchestrator调度器、Rule Engine规则引擎。这个选择背后是清醒的权衡微调成本太高且偏离目标微调一个大模型去学会“如何审核医疗器械GMP文件”需要海量标注数据、GPU资源、专业标注团队。而agency-agents的目标是“让懂GMP的人用自己的语言定义审核逻辑”不是让模型自学GMP。Orchestrator解决的是“谁在什么时候做什么”它不关心Agent内部怎么思考只确保当采购系统推送新订单先触发“供应商资质有效性Agent”查天眼查API内部黑名单若通过再触发“价格合理性Agent”比对历史成交价市场均价任一环节失败立即冻结订单并通知采购经理。这种状态机式的调度用Python的transitions库几行代码就能实现稳定可靠。Rule Engine承载经验的核心项目默认集成的是jsonpath-ng和自研的business-rule-engine支持类似$.invoice.amount $.contract.max_amount * 1.1这样的业务规则表达式。关键在于规则可版本化、可回滚、可AB测试。比如法务部更新了合同审批阈值只需发布新规则版本旧版本Agent仍按原逻辑运行新创建的Agent自动加载新版——这解决了业务规则高频迭代与系统稳定性的根本矛盾。注意项目刻意避免引入Kubernetes、Docker等重型运维组件。本地开发用uvicorn跑一个HTTP服务生产环境用Nginx反向代理Agent本身是无状态函数。这种“够用就好”的哲学让它能快速嵌入现有IT架构而不是要求整个组织为它重构基础设施。3. 核心细节解析从一份“客服工单分类Agent”配置看职业经验如何落地3.1 配置即文档YAML文件里的职业知识图谱项目所有Agent都由一个YAML文件定义这是经验沉淀的“源代码”。我们以customer_service_ticket_classifier.yaml为例拆解它如何把客服组长的多年经验编码化# 文件名agents/customer_service_ticket_classifier.yaml name: 客服工单分类岗Agent version: 2.1.0 description: 依据工单内容、用户等级、历史交互将工单分至VIP专线/技术故障/资费咨询/投诉升级四类严格遵循《客户服务分级响应SOP v3.2》 # 输入契约明确定义接收什么杜绝模糊 input_schema: ticket_content: type: string max_length: 5000 required: true user_tier: type: string enum: [bronze, silver, gold, platinum] required: true last_interaction_time: type: datetime format: YYYY-MM-DD HH:mm:ss required: false # 输出契约定义交付物格式确保下游可消费 output_schema: category: type: string enum: [vip_direct, tech_issue, billing_query, complaint_esc] confidence_score: type: number min: 0.0 max: 1.0 reason: type: string max_length: 200 # 核心规则引擎经验的结构化表达 rules: - id: vip_priority description: 铂金用户工单无论内容一律归VIP专线 condition: $.user_tier platinum action: category: vip_direct confidence_score: 0.99 reason: 用户等级触发VIP优先通道 - id: tech_keyword_match description: 内容含无法登录报错代码页面空白等关键词且非VIP用户 condition: $.ticket_content matches (无法登录|报错代码|页面空白|500错误) and $.user_tier ! platinum action: category: tech_issue confidence_score: 0.85 reason: 匹配技术故障关键词模式 - id: complaint_trigger description: 内容含投诉举报媒体律师且用户近7天有3次以上工单 condition: $.ticket_content matches (投诉|举报|媒体|律师) and $.last_interaction_time (now - 7 days) and count_previous_tickets() 3 action: category: complaint_esc confidence_score: 0.92 reason: 高危投诉信号高频交互触发升级流程 # 边界与兜底职业经验的“安全阀” fallback_strategy: default_action: category: billing_query confidence_score: 0.6 reason: 未匹配任何规则按常规资费咨询处理 escalation: - condition: confidence_score 0.7 target: senior_agentcs-team.internal message: 工单分类置信度低请人工复核{{ticket_content}} # 协作协议定义何时拉别人进场 collaboration_hooks: - event: category complaint_esc trigger: legal_compliance_agentinternal payload: {ticket_id: $.id, user_info: $.user_data}这份配置的价值远超一个分类器。它是一份活的SOP规则ID对应SOP条款编号description是给新人看的业务解释condition是可执行的逻辑fallback_strategy是兜底方案collaboration_hooks是跨部门协作约定。当客服组长离职新人不用读上百页文档直接看这个YAML就知道“为什么这个工单进了VIP通道”。3.2 规则引擎的实战技巧如何写出既准确又易维护的业务规则规则写得好不好直接决定Agent是否靠谱。我在复现这个客服Agent时踩过几个典型坑也总结出几条硬经验坑1过度依赖关键词忽略语义歧义初版规则用无法登录匹配结果把用户说“我无法登录贵司官网但能登录APP”也判为技术故障。后来改成condition: $.ticket_content matches 无法登录 and not $.ticket_content matches 但能登录.*APP——规则必须包含否定条件业务场景里“但是”“不过”“除了”往往是关键转折。坑2时间逻辑写错导致SLA违规原规则last_interaction_time (now - 7 days)本意是“7天内有交互”但实际写成了“交互时间晚于7天前”逻辑反了。正确写法是$.last_interaction_time (now - 7 days)——时间比较务必用避免因毫秒级误差漏掉临界点数据。坑3规则顺序引发意外覆盖把vip_priority规则放在最后结果铂金用户的“投诉”工单被complaint_trigger先捕获进了投诉升级队列。调整后所有高优先级规则VIP、紧急、合规必须前置规则引擎按序执行首个匹配即生效。独家技巧用“影子模式”灰度上线新规则不直接替换线上规则而是新增- id: tech_keyword_match_v2在Orchestrator里配置shadow_mode: true这样新规则只记录匹配结果不改变实际分类同时对比新旧规则差异。运行一周发现v2版将“页面加载慢”也纳入技术故障原版遗漏且误判率下降12%再全量切换。这是把A/B测试思想用在了职业经验迭代上。3.3 Agent间的协作协议如何让“律师Agent”和“财务Agent”像真人一样配合单个Agent再强也干不了跨职能的事。agency-agents的精髓在于collaboration_hooks定义的协作协议。我们看一个真实案例某公司要签一份海外云服务合同涉及数据出境合规与外汇支付。第一步法务初筛Agent输入合同PDF 《个人信息出境标准合同办法》输出{risk_level: high, clauses_to_review: [第5.2条数据处理者义务, 附件二安全措施清单]}触发协作event: risk_level high→trigger: data_compliance_officer_agent第二步数据合规官Agent接收法务传递的条款定位调用内部GDPR知识库输出{required_actions: [补充DPA附件, 增加数据泄露72小时通报条款], cost_impact: medium}触发协作event: cost_impact medium→trigger: finance_negotiation_agent第三步财务谈判Agent接收合规要求查询历史同类合同支付条款生成谈判要点{negotiation_point: 将DPA附件签署与首付款挂钩, fallback_position: 接受DPA但延迟30日生效}整个过程三个Agent之间不共享原始合同全文只传递结构化指令和必要片段既保护敏感信息又确保各司其职。Orchestrator全程记录事件链[法务]→[合规]→[财务]形成完整的决策审计日志。这比让一个“全能Agent”自己瞎琢磨靠谱十倍。实操心得协作协议的设计必须基于真实的组织汇报关系。我们曾把“财务谈判Agent”直接触发“CEO审批Agent”结果被业务方打回——因为实际流程是“财务谈完→法务复核→分管副总审批”。Agent的协作流必须是现实工作流的镜像否则就是纸上谈兵。4. 实操全流程从零部署一个“高校教务排课冲突检测Agent”4.1 环境准备与依赖安装5分钟搞定本地开发环境项目采用极简技术栈对新手友好。我用一台16GB内存的MacBook Pro实测全程无需Docker或云服务# 1. 创建独立Python环境推荐使用uv比venv更快 curl -LsSf https://astral.sh/uv/install.sh | sh source $HOME/.cargo/bin/uv uv venv .venv --python 3.11 source .venv/bin/activate # 2. 安装核心依赖注意项目不依赖PyTorch/TensorFlow纯CPU友好 uv pip install agency-agents0.4.2 pydantic2.6.4 jsonpath-ng1.6.0 # 3. 克隆项目并进入agents目录 git clone https://github.com/agency-agents/agency-agents.git cd agency-agents/agents # 4. 启动Orchestrator服务默认端口8000 uv run python -m agency_agents.orchestrator --host 0.0.0.0 --port 8000启动后访问http://localhost:8000/docs你会看到自动生成的FastAPI文档界面所有Agent的API都在这里。整个过程不到3分钟没有报错没有依赖冲突——这是项目刻意为之的体验让业务专家能绕过技术门槛直接聚焦经验建模。提示如果遇到jsonpath-ng安装慢可换国内源uv pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ jsonpath-ng4.2 编写第一个Agent教务排课冲突检测的YAML定义我们定义一个course_scheduling_conflict_detector.yaml解决高校教务处最头疼的问题同一教师同一时段被排两门课。name: 教务排课冲突检测岗Agent version: 1.0.0 description: 检测教师课表、教室课表、学生班级课表三重冲突依据《普通高等学校教学管理规程》第4.3条执行 input_schema: teacher_schedule: type: array items: type: object properties: teacher_id: {type: string} course_code: {type: string} start_time: {type: string, pattern: ^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$} end_time: {type: string, pattern: ^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$} classroom_id: {type: string} required: true classroom_schedule: type: array items: type: object properties: classroom_id: {type: string} course_code: {type: string} start_time: {type: string, pattern: ^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$} end_time: {type: string, pattern: ^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$} required: true class_schedule: type: array items: type: object properties: class_id: {type: string} course_code: {type: string} start_time: {type: string, pattern: ^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$} end_time: {type: string, pattern: ^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$} teacher_id: {type: string} required: true output_schema: conflicts: type: array items: type: object properties: type: {type: string, enum: [teacher, classroom, class]} details: {type: string} severity: {type: string, enum: [critical, warning]} summary: type: object properties: total_conflicts: {type: integer} critical_count: {type: integer} rules: - id: teacher_double_booking description: 同一教师在同一时段被安排两门及以上课程 condition: | let teacher_slots {}; for (item in $.teacher_schedule) { let key item.teacher_id _ item.start_time _ item.end_time; if (teacher_slots[key]) { teacher_slots[key] 1; } else { teacher_slots[key] 1; } } any(teacher_slots.values() 1) action: conflicts: | [ for (key, count in teacher_slots) { if (count 1) { { type: teacher, details: 教师 key.split(_)[0] 在 key.split(_)[1] 至 key.split(_)[2] 时段被排 count 门课, severity: critical } } } ] summary: | { total_conflicts: len($.conflicts), critical_count: len(filter($.conflicts, lambda x: x.severity critical)) } - id: classroom_overload description: 同一教室在同一时段被安排两门及以上课程 condition: | let room_slots {}; for (item in $.classroom_schedule) { let key item.classroom_id _ item.start_time _ item.end_time; if (room_slots[key]) { room_slots[key] 1; } else { room_slots[key] 1; } } any(room_slots.values() 1) # ... 后续规则省略完整版见项目examples目录这个YAML的关键突破在于它把“教师不能连上4节课”这种模糊要求转化成了可计算的时间槽time slot碰撞检测。start_time和end_time的格式强制校验避免了“下午2点”和“14:00”这类字符串歧义。规则里用伪代码风格的for循环和any()函数业务专家即使不懂编程也能看懂逻辑。4.3 调用Agent API用curl发送真实课表数据并解析结果准备好YAML后把它放到agents/目录下Orchestrator会自动加载。现在用curl测试# 构造一个故意制造冲突的教师课表张老师周二10:00-12:00被排两门课 curl -X POST http://localhost:8000/v1/agents/course_scheduling_conflict_detector/invoke \ -H Content-Type: application/json \ -d { teacher_schedule: [ {teacher_id: T001, course_code: CS101, start_time: 2024-03-12 10:00, end_time: 2024-03-12 12:00, classroom_id: R101}, {teacher_id: T001, course_code: MATH202, start_time: 2024-03-12 10:00, end_time: 2024-03-12 12:00, classroom_id: R202} ], classroom_schedule: [ {classroom_id: R101, course_code: CS101, start_time: 2024-03-12 10:00, end_time: 2024-03-12 12:00}, {classroom_id: R202, course_code: MATH202, start_time: 2024-03-12 10:00, end_time: 2024-03-12 12:00} ], class_schedule: [ {class_id: C101, course_code: CS101, start_time: 2024-03-12 10:00, end_time: 2024-03-12 12:00, teacher_id: T001}, {class_id: C202, course_code: MATH202, start_time: 2024-03-12 10:00, end_time: 2024-03-12 12:00, teacher_id: T001} ] } | jq .返回结果清晰明了{ conflicts: [ { type: teacher, details: 教师T001在2024-03-12 10:00至2024-03-12 12:00时段被排2门课, severity: critical } ], summary: { total_conflicts: 1, critical_count: 1 } }注意项目返回结果自带jq可解析的JSON Schema这意味着你可以直接用jq .conflicts[] | select(.severitycritical)提取高危冲突无缝接入学校现有的教务系统告警模块。Agent不是孤岛而是可插拔的业务能力模块。4.4 生产环境部署Nginx反向代理进程守护的轻量方案本地跑通只是开始。要让教务处每天用得上生产环境。我们用最朴素的方式# 1. 安装NginxMac用brewLinux用apt/yum brew install nginx # 2. 配置Nginx反向代理/usr/local/etc/nginx/nginx.conf location /api/ { proxy_pass http://127.0.0.1:8000/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # 3. 用systemd守护进程Linux或launchdMac确保服务永驻 # 创建/usr/local/lib/systemd/system/agency-agents.service [Unit] DescriptionAgency Agents Orchestrator Afternetwork.target [Service] Typesimple Userteaching-office WorkingDirectory/opt/agency-agents ExecStart/opt/agency-agents/.venv/bin/python -m agency_agents.orchestrator --host 127.0.0.1 --port 8000 Restartalways RestartSec10 [Install] WantedBymulti-user.target启动服务sudo systemctl daemon-reload sudo systemctl enable agency-agents sudo systemctl start agency-agents。教务系统前端只需调用https://jwxx.school.edu.cn/api/v1/agents/...完全感知不到后端是Python服务。没有K8s没有Service Mesh用最老派的工具解决最新锐的问题——这才是工程务实主义。5. 常见问题与排查技巧实录那些文档里不会写的坑5.1 问题速查表高频报错与根因分析报错信息根因分析解决方案经验备注ValidationError: Input data does not conform to schema输入JSON字段名与YAML中input_schema定义不一致如写成teacherId而非teacher_id用jq keys检查输入JSON字段名严格匹配YAML定义字段命名必须完全一致大小写、下划线都不能错RuleExecutionError: Unknown function count_previous_tickets自定义函数未在Rule Engine中注册在rule_engine.py中添加函数定义并在Orchestrator启动时注入所有业务函数必须显式注册不能依赖模型“猜”HTTP 503 Service UnavailableOrchestrator进程崩溃常见于内存溢出处理超大课表在YAML中增加memory_limit_mb: 512或优化规则避免全量遍历Agent不是万能的要主动设限防止一个坏输入拖垮全局No matching rule found输入数据未触发任何规则但业务上应有响应检查fallback_strategy.default_action是否配置或增加兜底规则如condition: true永远假设业务场景有“意外”规则集必须有出口Collaboration hook failed: Connection refused被调用的Agent服务未启动或地址错误用curl -I http://target-agent:8000/health检查目标服务健康状态协作是分布式系统每个环节都要独立可验证5.2 真实踩坑记录一次“学生退课”场景的深度复盘某高校希望用Agent自动处理学生退课申请规则很简单if 退课时间 开课前7天 then 批准 else 需教务主任审批。我们信心满满上线结果第一天就崩了——大量退课申请被错误批准。排查过程第一步查Orchestrator日志发现退课时间字段解析失败日志显示退课时间: 2024年3月12日第二步看YAML中input_schema定义退课时间: {type: datetime, format: YYYY-MM-DD}第三步发现问题根源——业务系统传的是中文日期格式而规则引擎只认ISO格式第四步临时修复在Orchestrator层加预处理用正则(\d{4})年(\d{1,2})月(\d{1,2})日转成YYYY-MM-DD第五步根本解决推动教务系统改造所有日期字段统一为ISO格式同时在YAML中增加preprocess钩子date_parse: zh_date_to_iso。这个坑教会我Agent的健壮性70%取决于输入数据的质量30%才是规则本身。项目后续版本增加了input_validation模块支持在入口处做格式清洗比如自动把“3月12日”转成“2024-03-12”把“¥1000”转成数字1000。不要指望业务系统完美Agent要当好“数据守门员”。5.3 性能调优实战如何让千人课表检测从12秒降到1.3秒初始版本处理全校1000名教师的课表耗时12秒无法用于实时排课系统。优化步骤定位瓶颈用cProfile分析90%时间花在jsonpath-ng的parse()和find()上每次规则都重新解析整个课表JSON缓存优化在Orchestrator中加入LRU缓存对相同结构的课表JSON只解析一次Schema后续复用规则精简合并重复条件把teacher_double_booking和classroom_overload的for循环合并为一次遍历数据预切片不传整个课表而是按周/按天切片Agent只处理当天数据用$.teacher_schedule[?(.start_time 2024-03-12 .start_time 2024-03-13)]过滤结果压缩关闭output_schema的详细校验只保留必要字段。最终效果处理1000人课表降至1.3秒QPS从8提升到120。性能不是靠堆硬件而是靠对业务数据分布的理解——课表冲突只发生在局部时间窗没必要全局扫描。5.4 经验总结职业Agent落地的三条铁律铁律一Agent的边界必须比人的边界更清晰人可以模糊处理“差不多行”Agent必须明确“行”或“不行”。比如采购Agent不能写“价格合理即可”而要写“单价≤历史成交均价×1.05且≥市场询价×0.9”。模糊是人的特权精确是Agent的义务。铁律二每一次协作都必须留下可追溯的“数字足迹”当法务Agent触发合规Agent时Orchestrator必须记录触发时间、触发条件、传递的字段、接收方响应、耗时。这些日志不是为了监控而是为了当出问题时能快速定位是哪个环节的规则失效而不是互相甩锅。铁律三经验迭代必须比业务变化慢半拍我们曾急于把最新版《数据安全法》条款塞进Agent结果发现基层执行时还在用旧版解读。后来改为新规则先以draft: true标记只供查看不执行等3个业务部门签字确认后再publish: true。Agent不是法典而是业务共识的快照。最后分享一个小技巧在每个Agent的YAML顶部加上maintainer: zhang.sanschool.edu.cn和last_reviewed: 2024-03-10。这样当新同事接手时第一眼就知道找谁、规则是否过期。最好的技术是让人感觉不到技术的存在只看到经验在顺畅流淌。