LlamaIndex 发布 legal-kb:基于 Index v2 的智能体检索参考应用
阅读原文· marktechpost.comLlamaIndex 把 RAG 从一次搜索变成了‘先找文件、再搜、再读、再 grep’的多步循环,对做合同审查、尽调的团队来说是个可抄的模板。
LlamaIndex 发布 legal-kb,一个基于 Index v2(LlamaParse Platform)的法律文档知识库参考应用。采用 Retrieval Harness 模式,赋予 Agent 四个文件系统风格工具:retrieve(混合语义检索,支持 rerank 和引用)、findFiles(精确/模糊文件名搜索)、readFile(带偏移量的原始内容读取)和 grepFile(正则匹配并返回字符位置)。Agent 需先调用 findFiles 确定文件清单,再依次使用其他工具定位内容。底层基于 Vercel AI SDK 6 的 ToolLoopAgent,可选用 OpenAI 或 Anthropic 模型,支持用户自带 API key。项目以 TanStack Start web app 形式运行,上传文件自动解析索引,同一文件名重复上传可产生版本,检索时通过版本元数据字段过滤。
LlamaIndex 在 GitHub 上发布了 legal-kb,一个公开参考应用。该应用被描述为一个基于 LlamaIndex Index v2(LlamaParse 平台)的法律文档知识库。该项目展示了一种团队称之为“检索工具集”(Retrieval Harness)的模式,用于智能体式检索。
这种方法不同于单次检索。它不是每次查询只做一次嵌入搜索,而是为智能体提供类文件系统的工具。智能体可以遍历一个庞大且不断演进的知识库来解决问题。这些工具模拟了工程师已经熟悉的操作:语义搜索与关键词搜索、正则表达式 grep、文件搜索以及读取。
什么是 legal-kb?
legal-kb 是一个可运行的 TanStack Start Web 应用,而非库。你可以登录、创建项目、上传文件,然后与智能体进行对话。每个项目都会镜像为一个受管理的 LlamaCloud Index v2。上传的文件会在后台自动被解析和索引。对话智能体随后在每次交互中实时查询该索引。
通俗解释“检索工具集”(Retrieval Harness)
该工具集为你的文档提供了一条持久化数据管道。它连接数据源、建立索引并保持更新。在这条管道之上,它向智能体暴露一组工具。
这些工具有意设计得接近文件系统操作。智能体可以列出文件、读取文件、在文件内执行 grep 或运行混合搜索。由于这些工具是通用的,你可以将该工具集接入到你自己的智能体中。
四个智能体工具
位于 src/lib/agent.ts 中的智能体被赋予了四个工具。每个工具都对应一个 Index v2 检索 API。下表列出了它们的实现方式。
| 工具 | 后端 API | 关键参数 | 功能说明 |
|---|---|---|---|
| retrieve | beta.retrieval.retrieve | query, top_k, score_threshold, rerank_top_n, file_name, file_version | 执行混合语义搜索;可选重排序;返回文本块及引用 |
| findFiles | beta.retrieval.find | file_name, file_name_contains | 按精确名称或子串搜索文件;自动分页 |
| readFile | beta.retrieval.read | file_id, offset, max_length | 读取原始文件内容,支持偏移量和长度窗口 |
| grepFile | beta.retrieval.grep | file_id, pattern, context_chars, limit | 在单个文件中匹配模式;返回字符位置 |
系统提示词强制规定了执行顺序。智能体必须先调用findFiles建立文档清单,然后通过retrieve缩小范围,最后在用readFile或grepFile确认确切措辞后才能进行引用。
底层工作原理
上传过程遵循src/lib/files.ts中清晰的流水线。数据字节被推送到项目的LlamaCloud源目录。通过Prisma将File和ProjectFile记录写入PostgreSQL。索引同步会被触发但不等待;UI会轮询状态直至就绪。
版本控制的范围限定在(项目,文件名)这一键值对。将nda.pdf重新上传到同一项目会产生并存的v1、v2、v3版本。检索层会对版本元数据字段进行过滤。这样就实现了知识库本身的版本控制。
该智能体使用了Vercel AI SDK 6中的ToolLoopAgent。你可以在每次轮次中选择OpenAI或Anthropic,并自带自己的API密钥。推理过程是流式传输的:Claude模型使用扩展思考;OpenAI推理模型使用中等推理强度。
以下是对retrieve工具和智能体的精简但忠实的描述。
import { LlamaCloud } from '@llamaindex/llama-cloud'
import { tool, ToolLoopAgent } from 'ai'
import { z } from 'zod'
import { makeCitationId } from './citations'
// One tool closure per index. Wraps Index v2 retrieval APIs.
function createLlamaParseTools(apiKey: string, projectId: string, indexId: string) {
const client = new LlamaCloud({ apiKey })
const retrieve = tool({
description: 'Run a semantic retrieval query against an index.',
inputSchema: z.object({
query: z.string(),
top_k: z.number().nullable(),
score_threshold: z.number().nullable(),
rerank_top_n: z.number().nullable(), // set to enable reranking
file_name: z.string().nullable(), // metadata filter
file_version: z.number().nullable(),
}),
execute: async ({ query, top_k, score_threshold, rerank_top_n, file_name }) => {
const custom_filters = file_name
? { file_name: { operator: 'eq' as const, value: file_name } }
: undefined
const response = await client.beta.retrieval.retrieve({
index_id: indexId,
project_id: projectId,
query,
top_k,
score_threshold,
rerank: rerank_top_n != null ? { enabled: true, top_n: rerank_top_n } : undefined,
custom_filters,
})
// Return a model-readable list plus citations that drive the UI chips.
const citations = response.results.map((r) => ({
id: makeCitationId(), // e.g. "c7f2qa"
fileName: r.metadata?.file_name,
score: r.rerank_score ?? r.score ?? null,
preview: r.content.slice(0, 500),
}))
const formatted = response.results
.map((r, i) => `### Result #${i + 1}\n\n${r.content.slice(0, 600)}`)
.join('\n\n---\n\n')
return { formatted, citations }
},
})
// findFiles / readFile / grepFile follow the same shape, backed by
// client.beta.retrieval.find / .read / .grep
return { retrieve /* , findFiles, readFile, grepFile */ }
}
export function buildAgent(model, apiKey: string, projectId: string, indexId: string) {
return new ToolLoopAgent({
model,
tools: createLlamaParseTools(apiKey, projectId, indexId),
instructions:
'Always call findFiles first, ground every answer in the documents, ' +
'and cite ids inline as `cite:<id>`.',
})
}回答附带可视化引用。每个被检索的文本块会获得一个短ID,例如cite:c7f2qa。智能体在内联中引用该ID,UI则会渲染一个可点击的引用标签。点击标签会打开该源页面的截图,并用边界框高亮出被引用的文本。
朴素RAG与智能体检索框架
该框架是一种与单次RAG不同的执行模型。下面的对比侧重于行为差异。
| 维度 | 朴素/单次RAG | 智能体检索框架(索引v2) |
|---|---|---|
| 检索流程 | 每次查询执行一次向量搜索 | 多步骤工具循环:find → retrieve → read/grep |
| 搜索模式 | 仅向量相似度 | 混合语义搜索、关键词和正则表达式grep |
| 上下文 | 固定的前k个文本块 | 智能体按需读取完整文件或窗口 |
| 时效性 | 静态索引 | 持久化流水线,带同步和版本控制 |
| 精度控制 | 大部分隐藏 | 暴露top_k、score_threshold、rerank_top_n |
| 引用 | 文本块ID | 带有页面截图和边界框的可视化引用 |
| 最佳适用场景 | 简短问答 | 长周期文档任务 |
用例及示例
该设计针对的是智能体需要处理大量文档集的领域。给出的示例是法律和金融科技。
- 考虑一个合同问题:“终止主服务协议(MSA)需要什么通知?”智能体会列出文件、运行检索、然后精准定位到具体条款。它会在答案中引用具体页码。
- 考虑在数据室中进行尽职调查:智能体可以按名称查找文件,然后读取每个候选文件。它可以在不打开每个PDF的情况下交叉核对条款。
- 考虑一个带版本控制的策略库:由于检索功能接受文件版本过滤参数,智能体可以查询特定版本。这支持随时间推移的变更追踪。
参考实现
核心要点
- legal-kb 是一个公开的参考应用,展示了在 LlamaIndex Index v2 上实现的智能体检索能力。
- 该智能体拥有四个类文件系统的工具:检索(混合搜索)、查找文件、读取文件和grep文件。
- 一个持久化管道负责解析、索引、同步以及每个文件的版本控制。
- 答案包含可视化引用:页面截图,并在引用文本上标注了边界框。
- 技术栈为 TanStack Start、AI SDK 6、Prisma 和 WorkOS,并采用按用户加密的密钥。