具备LlamaIndex检索功能与HITL编码技术的LangGraph研究代理
基于格式识别的分块处理、结构化意图路由、并行专家检索器以及带中断控制的命令行接口编码,能够安全地将论文转化为可执行的实验。
将学术论文转化为可运行的实验通常需要经历阅读、总结、编码和调试等繁琐步骤。基于状态的多智能体系统能够分担更多工作:使用 LangGraph 进行路由处理,LlamaIndex 用于专业检索,再通过人工审核机制配合 CLI 编码工具。
1. 智能数据摄取:并非所有数据块都相同
使用统一策略盲目分割 PDF、Python 代码和 CSV 文件会降低检索质量。在将数据索引到 ChromaDB 之前,应根据格式进行合理分割——散文采用叙事段落划分,代码采用逻辑块划分,表格则按行进行分割:
# 5. Setup Chunkers
pdf_chunker = SentenceSplitter(chunk_size=512, chunk_overlap=50)
python_chunker = CodeSplitter(language='python')
csv_reader = CSVReader(concat_rows=False)
# 6. Route and Chunk Data
for doc in documents:
file_name = doc.metadata.get("file_name", "")
if file_name.endswith(".pdf"):
nodes = pdf_chunker.get_nodes_from_documents([doc])
elif file_name.endswith(".py"):
nodes = python_chunker.get_nodes_from_documents([doc])
elif file_name.endswith(".csv"):
# CSVs are chunked row-by-row by our custom reader
all_nodes.append(doc)
这样一来,嵌入模型(例如 Ollama 的 all-minilm)就能反映数据结构,而非任意的字符窗口。
2. LangGraph 的核心功能:意图分类
LangChain提供模型、提示词和工具;LangGraph负责控制流程。一个共享的State字典在各个节点间传递数据。自由文本关键词路由方式较为脆弱,因此通过Pydantic实现结构化输出,可让本地模型如llama3.2:3b输出Literal类型的意图:
class IntentClassifier(BaseModel):
message_intent: Literal['chat', 'code', 'knowledge'] = Field(
...,
description="Classify the user intent. 'code' for implementation, 'knowledge' for research details, 'chat' for general tasks."
)
这样一来,条件边就能在无需解析无意义内容的情况下可靠地分发任务。
3. 知识路径:并行检索
复杂的研究问题很少能仅通过一次相似度搜索解决。可将知识路径扩展为四个LlamaIndex智能体——abstract_agent、methodology_agent、limitations_agent和conclusion_agent——每个智能体负责特定的查询任务。利用LangGraph的operator.add函数合并各智能体的部分检索结果,避免不同内容相互冲突:
class State(TypedDict):
messages: Annotated[list, add_messages]
message_intent: str | None
next_node: str | None
context: Annotated[list[str], operator.add] # Safely appends parallel findings
analyst_agent会读取整合后的上下文,并总结出优缺点及存在的不足。
4. 将研究转化为行动:人工干预的编码流程
通过编码路径,可将意图转化为子进程指令,进而传递给编码命令行界面。未经控制的shell访问存在风险,因此LangGraph会通过interrupt()功能暂停执行以等待批准:
def accept_coding(state: State):
user_prompt = state['messages'][-1].content
decision = interrupt(f'About to run Claude Code with request:\n\n{user_prompt}\n\nApprove? (yes/no, or type a revised request)')
text = str(decision).strip().lower()
if text in ['y', 'yes', 'approve', 'ok']:
return {'next_node': 'coding_agent'}
if text in ['n', 'no', 'deny', 'cancel']:
return {'messages': [{'role': 'assistant', 'content': 'Coding request denied.'}], 'next_node': 'denied'}
# Allows the user to dynamically edit the prompt mid-flight
return {'messages': [{'role': 'user', 'content': text}], 'next_node': 'accept_coding'}
获得批准后,代码将在沙箱式工作环境中执行,其输出结果会实时反馈到聊天界面中。
总结
将信息检索(LlamaIndex)与状态管理及路由功能(LangGraph)分开,可以构建出模块化的架构,使其能够在人类对关键决策进行把控的同时完成研究及行动。
运营经验
- 由于考虑了格式因素进行分块处理,因此当代码检索不再返回不完整的函数时,这一做法便显现出了优势。
该框架的产物就是图结构:节点是可以替换的,但状态契约与审批机制才是确保从研究到代码的转化过程能够安全地每日运行的关键。
端到端流程说明
- 使用格式专用分割器导入论文与笔记本;当数据源发生变化时重新构建Chroma集合。
- 将用户的表述分类为知识类或编码类(随着产品发展可细化分类标准)。
operator.add将结果合并,最后由分析器进行综合处理。这样的循环足以用一个稳定的智能体界面替代一堆临时的笔记本。