CASE STUDY / 企业 AI Agent 工程
从合同修订到
可信的 AI 工作流
解读 Uber Redlining Agent:把检索、专家反馈和规则约束,组合成可供人审阅的条款建议。
案例与学习目标
学习主线:把“生成一个答案”拆成一组可检查的中间结果,让领域专家能够审阅、纠正,并为下一次任务留下可用的经验。
Uber 的 LRA 嵌入 Word,由律师审核建议。系统经历 RAG、反馈、语气、代理式改写四次迭代,并结合规则库。技术组件包括 React / TypeScript、Python / LangGraph、OpenSearch 和 Redis;反馈学习主要通过运行时上下文完成,无需手工微调。[1]
理解系统:02–04,明确任务、演进和边界。
拆解核心:05–08,理解证据、记忆、约束和编排。
动手迁移:09–12,设计写回、评估并完成练习。
下文以自主工程分析为主。蓝色编号链接指向来源;“教学方案 / 合成示例”表示本文推导,不代表 Uber 的生产代码或完整内部设计。
先定义任务与状态
Redlining 指在合同谈判中标记、审阅和回应文字修订。实现时,任务对象应是一处有上下文的变更,而不是把整份合同直接交给模型,期待它一次完成所有判断。
输入:可定位的变化
原句、对方修订、上下文、条款位置、文档版本,以及适用政策范围。
“修改了什么”属于文本事实;“想达到什么效果”属于推断。两者应分开保存。
输出:可审阅的建议
动作、风险、证据、拟议条款和对外说明,另附需要人工判断的问题。
将证据和最终文本一起呈现,专家才能快速发现错误来自哪里。
| 状态 | 含义 | 进入下一步的条件 |
|---|---|---|
ACCEPT | 建议接受对方这处修订 | 仍需确认政策范围、文档版本与人工选择 |
REJECT | 建议保留原条款或拒绝修订 | 给出证据及简明说明 |
MODIFY | 建议提出新的折中条款 | 拟议文本通过术语与约束检查 |
NEEDS_REVIEW | 教学扩展:证据不足、冲突或校验失败 | 明确暴露未解决的问题,由专家处理 |
重要的状态分离:模型建议、律师决定、实际写回是三个事件。把它们存成同一个“已接受”字段,会失去评估与追踪错误所需的信息。
四次迭代的技术启示
阶段名称对应原文;下面的问题与实现建议为教学分析。Phase 表示演进顺序,不代表具体发布日期。[1]
从检索资料开始
要追问:检索返回的段落,是否真的能支持当前动作?相似话题可能涉及不同责任主体、范围或例外。
可做实验:分别用原句、修订文本和意图摘要查询,同一组专家标签评估证据召回。
把纠正变成可复用样本
要追问:“不满意”说明了什么?如果没有正确动作、修改文本和理由,后续任务很难知道该如何纠正。
可做实验:保持模型与测试集相同,对比只存赞踩、存动作、存完整纠正的效果。
把表达优化独立出来
要追问:一句更温和的话,是否偷偷改变了已经确定的立场?先固定决定与不可改变事实,再优化措辞。
可做实验:让专家分别评“立场正确”和“表达可用”,避免用一个总分掩盖问题。
从动作标签进入条款改写
要追问:改写增加了哪些新义务?一段流畅的替代条款,需要同时满足范围、定义、金额、期限和例外条件。
可做实验:将生成前后的结构化约束逐项比较,输出失败项供专家审阅。
演进规律:每新增一项能力,也应新增一种可检查的输出。更长的提示词,不能替代证据、状态和校验边界。
架构与数据流
可以把此类系统设计成三层:文档交互、决策工作流、证据与记忆。每层负责不同的失败模式:定位错误、推断错误、证据错误不应混在一起调试。
三类存储,三种生命周期
设计推论:会话状态允许短期变化;规则必须有权威版本;经验需要带范围和时效。只按“向量数据库 / 缓存”划分,容易忽略数据治理上的差异。
检索键与证据选择
检索质量取决于“查询表达”和“入库表达”能否对应。先明确希望找回的是同一条款、同一谈判意图,还是同一适用政策,再选嵌入文本与过滤条件。
原文分别讨论意图向量和原句锚定,未公开统一查询计划。下表是本文建议的教学拆分。[1]
| 检索目标 | 查询 ↔ 入库表达 | 应限制的范围 |
|---|---|---|
| 条款对应规则 | 原句或规范化条款 ↔ 规则关联的目标条款 | 模板、规则版本、业务线、适用主体 |
| 类似谈判经验 | 本次意图摘要 ↔ 历史意图摘要 | 条款类型、责任主体、政策范围 |
| 同源历史记录 | 模板条款锚点 ↔ 历史条款锚点 | 模板版本及兼容关系 |
修订 A:将服务方责任从“有限责任”改为“无限责任”。
修订 B:将客户责任从“无限责任”改为“有限责任”。
两处包含相近词汇,但责任主体和方向相反。重排时应核对:谁的责任、扩大还是缩小、针对哪些损失、是否有例外。仅凭相似度高低不能判断经验可迁移。
建议的四道检索检查
- 授权与范围:先限制允许访问的业务、模板和政策数据。
- 候选召回:向量搜索或条款锚点搜索找回可能相关的证据。
- 语义重排:检查责任主体、变更方向和约束是否对齐。
- 上下文选择:在有限预算中保留相关、有效且不重复的证据,暴露冲突。
OpenSearch 提供搜索中过滤以及其他过滤方式;后置过滤可能让返回候选数不足。具体策略取决于所用引擎和版本,不能假设所有过滤位置效果相同。[4]
评估必须分层:先用专家标签检查正确证据能否被找回,再评动作和文本。否则“判断错误”可能其实是模型从未见到正确规则。
反馈记忆与时间权重
运行时学习可以改变下一次给模型看的例子,而不更新模型参数。这里的关键是构建有标签、可过滤的经验库,不能把所有历史对话无差别塞入提示词。
{
"feedback_id": "synthetic-fb-001",
"template_id": "demo-services-v3",
"clause_anchor": "liability.cap",
"policy_version": "demo-2026-10",
"original_text": "责任上限为约定费用。",
"counterparty_text": "责任不设上限。",
"intent": "移除服务方责任上限",
"ai_action": "ACCEPT",
"lawyer_action": "MODIFY",
"lawyer_final_text": "责任上限为双方另行约定的金额。",
"lawyer_reason": "保留上限原则,金额需要另行确认。",
"error_type": "wrong_policy_application",
"created_at": "2026-10-11T00:00:00Z",
"review_status": "approved_for_retrieval"
}
这些文字只用于演示反馈结构。“最终采用了什么”和“为什么采用”,比一枚赞踩更接近可复用监督信号。
时间衰减:降低旧经验权重
下面给出一种可复现的指数衰减定义。设经验年龄为 d 天、半衰期为 H 天:
年龄到达一个半衰期,权重为 0.5;两个半衰期为 0.25。权重表示样本选择偏好,不表示模型置信度。
参数用于展示公式。先筛适用范围,再做衰减;失效规则不能靠“权重较低”继续约束当前任务。
经验库的三个分离
- 当前政策与历史选择分离:旧案例不能覆盖新版本规则。
- 偏好与真值分离:某次谈判接受一项例外,不代表所有客户都可以接受。
- 训练上下文与评测样本分离:按合同或模板族隔离,避免近重复样本泄漏。
示例配比也应受控。如果历史记录几乎都是接受,模型可能把多数动作当成默认策略。采样可以保证动作覆盖,但应另用真实业务分布评估整体效果。
规则、生成与语气
为此类系统设计清晰的优先级:有效的权威规则约束可行解,经验帮助选择可行解,语气只改变表达。让三者在同一次自由生成中相互竞争,很难解释冲突如何解决。
| 层 | 解决什么问题 | 教学控制方法 |
|---|---|---|
| 权威规则 | 哪些条件必须满足 | 明确版本、范围、例外及规则优先级 |
| 经验与生成 | 允许范围内,什么建议最合适 | 带来源样本;输出结构化动作和条款 |
| 语气调整 | 如何清晰、专业地解释决定 | 锁定动作、金额、期限、责任和例外 |
| 最终校验 | 文本是否仍满足约束 | 程序检查 + 语义审查 + 专家确认 |
规则优先不等于规则必然正确:规则适用性的识别可能出错。即使命中后强制执行,也要单独评估误匹配、漏匹配与例外处理。
把“修改条款”变成约束求解
已定义术语:保留原文主体名称与定义,不新造“关联方”等概念。
数值约束:金额、倍数、天数和币种必须来自输入或明确允许的备选方案。
义务约束:不扩大赔偿对象、损失范围或履行主体。
例外约束:必要例外和适用条件不能在润色时丢失。
程序容易检测未授权的数字变化;模型更适合辅助检查语义变化。但第二次模型调用仍可能犯错,因此应将校验发现作为可审阅证据,而不是把“模型说通过”当作质量保证。
一个可管理的语气提示结构
任务:改写下面的说明,使其直接、专业、简洁。
不可改变:
- action / policy_constraints / numeric_terms
- 责任主体、承诺范围、必要例外
- 不添加事实、承诺或未获授权的让步
风格要求:
- 用清晰陈述解释建议和依据
- 删除无关寒暄、夸张语气和对抗措辞
输出:
- rewritten_comment
- preserved_constraints
- unresolved_questions
实现建议:工程团队维护输入输出契约,领域专家维护风格示例与内容边界。每次提示版本更新都应跑同一组回归案例。
图编排与失败路径
LangGraph 支持把确定性步骤和模型步骤组织在有状态的图中,并提供持久化与人工介入能力。框架提供编排能力;节点契约、证据优先级与业务正确性仍由应用设计承担。[3]
async def analyze(change, scope):
# 这三个任务都可仅依赖输入快照
intent, risk, rules = await gather(
detect_intent(change),
assess_risk(change),
retrieve_current_rules(change.original, scope)
)
# 依赖 intent,不能提前假装已拿到意图
examples = await retrieve_feedback(intent, change.anchor, scope)
evidence = select_valid_evidence(rules, examples)
if evidence.missing or evidence.conflicting:
return needs_review("证据缺失或冲突", evidence)
decision = await decide(change, intent, risk, evidence)
clause = None
if decision.action == "MODIFY":
clause = await draft_clause(change, decision, evidence)
comment = await style_comment(decision.comment,
locked=decision.constraints)
checks = await validate(change, decision, clause, comment, rules)
if not checks.passed:
return needs_review("校验未通过", checks)
return reviewable_suggestion(
decision, clause, comment, evidence,
source_version=change.document_version
)
# 人工批准是独立事件;真正写回前再次检查文档版本
# 未通过校验的结果也可展示,但必须标明待处理原因。
延迟优化先看关键路径
把意图、风险与规则查找记为 Tᵢ、Tᵣ、Tₚ,反馈检索记为 T𝒇。上面的示例先等三项结束再检索反馈,其前半段耗时约为:
进一步可以在意图一完成时就启动反馈检索,不必等风险分支;此时近似变为 max(Tᵢ + T𝒇, Tᵣ, Tₚ)。这是一种调度改进,前提是没有隐藏的数据依赖。
| 失败情形 | 建议行为 | 应记录的证据 |
|---|---|---|
| 检索超时 / 无规则 | 标记证据不足,供人工处理 | 查询范围、超时节点、是否命中 |
| 模型输出结构不合法 | 有限重试;仍失败则停止自动路径 | Schema 错误、提示与模型版本 |
| 校验失败 | 呈现具体失败项,不直接写入 | 违规约束、拟议文本差异 |
| 写回时文档已变化 | 重新定位并分析,保留审阅记录 | 旧版本、新版本、失效位置 |
文档集成与写回
把 AI 放入文档工具,真正困难的是保持“模型看到的文本”与“用户正在编辑的文本”一致。模型输出很准确,如果写错条款或覆盖了后续修订,整个任务仍然失败。
理解 Office.js 的同步边界
Office.js 的对象通常是代理对象。读属性前需要排队加载,再调用 context.sync();多条操作可以批量同步。插件与 Office 应用之间存在异步边界,因此应尽量减少不必要的往返。[2]
await Word.run(async (context) => {
const selection = context.document.getSelection();
selection.load("text");
await context.sync();
const snapshot = { text: selection.text };
// 将纯数据快照传给分析服务;不要把代理对象当作业务数据。
});
示例依据 Office.js 的代理与批处理模型编写。真实实现应确认目标 Word 客户端所支持的 API requirement set。
建议的写回协议
- 读:提取条款快照、范围标识与内容指纹;保留原文和修订后的文本。
- 析:后台使用快照生成建议,并返回对应版本、证据和校验结果。
- 审:用户选择接受、拒绝或继续修改,单独保存这个事件。
- 写:检查目标位置与文本指纹;若发生变化,重新分析或重新确认。
- 记:确认写回结果后存审阅反馈。重复请求应通过操作 ID 避免重复写入。
只用缓存不够:缓存解决重复读取成本,内容指纹与版本检查解决过期快照。二者应一起设计。
另一个重要边界是把合同文本当作待分析数据。对方文本中的指令式措辞不能改变应用规则;检索数据也要受用户权限和业务范围限制。这些应通过工具接口和查询约束实现,不能只靠提示词。
评估与指标解读
一个总准确率难以回答“系统在哪里有用”。应把证据、决策、改写、表达和业务耗时分开测量,再看它们如何共同影响专家审阅。
| 层次 | 度量方法 | 它能回答的问题 |
|---|---|---|
| 证据 | 专家标注的 Recall@k、有效规则召回率 | 应出现的证据是否进入上下文 |
| 动作 | 分类混淆矩阵、各动作 Precision / Recall | 错误集中在接受、拒绝还是修改 |
| 高代价错误 | 违规接受率;规则冲突漏报率 | 系统是否把不应放行的建议放行 |
| 改写 | 约束违反率、专家修改量、实际采用率 | 生成条款是否减少后续劳动 |
| 表达 | 专家盲评:清晰、专业、立场保持 | 语气优化有没有损害原意 |
| 业务 | 配对任务耗时、返工次数、P95 响应延迟 | 是否让整个审阅过程更高效 |
怎样审慎阅读 91% 和 >20%
- 核对分析单位:一处修订、一项动作、一份合同是不同的分母。
- 观察错误代价:将违规修改误判为接受,可能比把可接受项交给人工处理代价更高。
- 检查对照:案例难度、专家经验和辅助功能使用情况应尽量可比。
- 要求切片:按模板、条款类型和新旧政策分别看,防止高频简单项掩盖弱项。
这些是对已报告指标的分析问题,不据此推断原文数据无效,也不补造其测试方法或置信区间。
LLM 评分器应怎样使用
将模型评分器用于持续筛查,再用专家标签校准。检查它是否偏好更长的说明、是否被“听起来专业”误导,以及它和生成模型是否共享同一种错误。评分器的判断不能自动转成新规则。
回归测试的触发点:模型、提示、嵌入方式、检索过滤或规则版本发生变化时,重复运行冻结的评测集;分别定位证据退化和生成退化。
最小实现与演进
学习实现可以从一个模板族和少量条款类型开始。先让输入、证据与人工纠正形成完整链路,再添加更复杂的生成或框架能力。
| 阶段 | 交付内容 | 进入下一步前验证 |
|---|---|---|
| 1 · 离线基线 | 结构化变更输入、版本化规则、动作输出 | 能复现样本;动作与证据可追踪 |
| 2 · 反馈检索 | 完整专家纠正、意图键、范围过滤 | 与无反馈基线比较;无评测泄漏 |
| 3 · 条款生成 | 修改分支、语气提示、约束校验 | 没有新增未授权义务;失败可审阅 |
| 4 · 文档试用 | 定位、审阅、版本校验与写回记录 | 同一建议不会写错位置或重复应用 |
三个练习:每次只改变一个因素
A / 检索键实验
为同一批合成修订标注正确规则。比较原句、修订句、意图摘要的 Recall@k。记录哪些错误来自责任主体相反、变更方向相反或模板漂移。
B / 时间权重实验
创建新旧政策冲突样本。先不加范围过滤,仅使用时间衰减;再加有效政策过滤。观察旧样本权重低时是否仍能污染结果。
C / 语气保持实验
准备含金额、天数、责任对象和例外的说明。分别评改写流畅度与约束保持率,检查最流畅的输出是否也最准确。
从工作流到 Harness,先明确迁移收益
Agent harness 可以承担工具调用、上下文管理和执行控制。是否采用它,应看是否减少适配与状态管理成本,并保留明确的审批、证据与失败边界。更灵活的执行方式,本身不能证明更适合一个有固定审阅流程的任务。
原文把 harness、法律本体与知识图谱列为探索方向;不应把它们描述成已完成部署或已验证收益。[1]
可迁移的方法:确定任务单位 → 找到可检查证据 → 收集专家纠正 → 固定约束与写回边界 → 用业务结果检验系统价值。
自测与参考解答
先自行回答,再逐项展开。题目检验对检索、编排、约束和评估的理解。
1. 找到了相似的责任条款,为什么仍不能直接复用历史决定?
语义相似不保证责任主体、修改方向、例外和适用政策相同。应先按范围过滤,再检查关键语义;历史结果只在相同约束下具有参考价值。
2. 一条三年前的反馈非常相似,时间衰减能保证不会用错吗?
不能。衰减只降低选择偏好,旧样本仍可能被选中。先确认政策有效性与适用范围,再对有效候选做时间加权。
3. 哪些节点可以并行,哪些不能?
仅依赖输入快照的意图识别、风险评估和原句规则检索可以并行。以意图为查询键的反馈检索要等意图完成;决策要等所需证据;生成后的校验必须等待生成。
4. 模型建议通过了语义校验,为什么写回前仍要检查版本?
校验检查的是分析时的快照。用户随后可能修改或移动条款,使建议失去适用位置。写回要重新核对目标范围及内容指纹,并避免重复执行。
5. 决策准确率提高,为什么实际审阅仍可能变慢?
说明冗长、证据难找、条款定位错误、生成需要大量修改或响应过慢,都可能抵消决策收益。应同时测实际耗时、返工、采用率和延迟。
6. 运行时反馈学习与模型微调有什么区别?
运行时反馈学习通过检索与样本选择改变输入上下文;微调通过训练改变模型参数。前者的更新粒度可以是删除一条案例或切换规则版本,但效果仍需通过独立评测确认。
来源与阅读边界
- [1] Uber · Scaling AI in Legal: Building Uber’s Redlining Agent案例主来源。发布于 2026-10-08,访问于 2026-10-11。本文仅压缩列出关键事实,其余围绕案例作工程推导。
- [2] Microsoft Learn · Application-specific API model用于核对 Office.js 代理对象、load / sync 与批处理模型。访问于 2026-10-11。
- [3] LangChain · LangGraph overview用于核对有状态图编排、持久化及人工介入能力。访问于 2026-10-11。
- [4] OpenSearch · Filtering vector search results用于核对向量检索过滤方式。具体能力需匹配部署引擎和版本。访问于 2026-10-11。
原文没有提供完整生产代码、统一检索查询计划、全部提示词、完整评测数据或可复现实验配置。本文的架构图、Schema、公式演示、伪代码、失败路径和练习均为教学设计。