☰
DeepSeek-Agent-Harness-2026终极指南-第11章第52节-上下文工程进阶-文件树注入:让Agent看见项目全貌
2026/10/3 8:42:32 网站建设 项目流程

DeepSeek Agent Harness 2026终极指南 - 第11章第52节 文件树注入:让Agent看见项目全貌

第51节解决了"历史太长",但还有个问题——Agent 不知道项目长什么样。你让它"改一下用户模块的代码",它得先猜文件在哪、有哪些文件、依赖是什么。这节做文件树注入:把项目结构树、README、pyproject、git 状态一起塞进上下文,让 Agent 一启动就"看见"项目全貌,不用瞎猜、不用反复 grep。

本文导航

  • Agent 为什么需要"看见"项目
  • 项目结构树生成与token控制
  • 重要文件自动注入
  • git状态与最近提交注入
  • 完整实现:context_inject.py
  • 实测:Agent 一启动就懂项目
  • 小结

Agent 为什么需要"看见"项目

想象两个场景:

场景A:没有文件树。你问 Agent"改一下登录逻辑",Agent 的对话是:

Agent: 让我先找找登录相关的代码。 → grep "login" → 找到 auth.py、login.py、user.py 三个文件(但不知道哪个是主入口 → 还得再读 README、读 pyproject 确定项目结构 → 来回好几轮,才搞清楚项目长什么样

场景B:有文件树注入。你问同样的问题,Agent 一启动就看到:

项目结构: deep_pilot/ ├── config.py # 配置 ├── client.py # DeepSeek 客户端 ├── auth.py # 登录认证逻辑 ├── ...
Agent: 我看到了,auth.py 是登录认证模块,直接改它就行。

环境感知是 Agent 效率的关键。注入项目结构能让 Agent 少做很多无用功。

项目结构树生成与token控制

用os.walk或Path.rglob生成目录树:

# deep_pilot/context_inject.py —— 环境注入 v0.6from__future__importannotationsfrompathlibimportPathfromdeep_pilot.loggerimportget_logger logger=get_logger(__name__)# 忽略的目录(生成文件树时跳过)IGNORE_DIRS={".git","node_modules",".venv","__pycache__","dist","build",".pytest_cache",".tox"}# 忽略的文件IGNORE_FILES={".pyc",".pyo",".so",".dll",".exe"}defgenerate_tree(root:Path,max_depth:int=3,max_files:int=200)->str:""" 生成项目结构树。 max_depth: 最大目录深度 max_files: 最多列出的文件数 """root=Path(root).resolve()lines=[]file_count=0defwalk(dir_path:Path,prefix:str,depth:int):nonlocalfile_countifdepth>max_depth:lines.append(f"{prefix}...(深度超限,已省略)")returnentries=sorted(dir_path.iterdir(),key=lambdap:(p.is_file(),p.name))forentryinentries:# 跳过忽略项ifentry.nameinIGNORE_DIRS:continueifentry.is_file()andentry.suffixinIGNORE_FILES:continueiffile_count>=max_files:lines.append(f"{prefix}...(文件数超限,已省略)")returnifentry.is_dir():lines.append(f"{prefix}├──{entry.name}/")walk(entry,prefix+"│ ",depth+1)else:lines.append(f"{prefix}├──{entry.name}")file_count+=1lines.append(f"{root.name}/")walk(root,"",1)return"\n".join(lines)

token 控制的三板斧:

  1. max_depth:限制目录深度,太深的目录不展开
  2. max_files:限制文件数量,超过就省略
  3. 忽略目录:.git、node_modules等大目录直接跳过

一个典型的中型项目,生成的文件树约 800-1500 token,可接受。

重要文件自动注入

除了结构树,几个"关键文件"值得完整注入——它们是理解项目的钥匙:

definject_important_files(root:Path)->str:"""注入重要文件内容(README/pyproject等)"""important_files=["README.md","pyproject.toml",".env.example",]parts=[]forfnameinimportant_files:fpath=root/fnameiffpath.exists():content=fpath.read_text(encoding="utf-8",errors="ignore")# 限制每个文件最多注入 1000 字符iflen(content)>1000:content=content[:1000]+"\n...[已截断]"parts.append(f"###{fname}\n```\n{content}\n```")return"\n\n".join(parts)

为什么是这几个文件?

  • README.md:项目是干嘛的、怎么用,一目了然
  • pyproject.toml:依赖、版本、构建配置,理解技术栈
  • .env.example:需要哪些环境变量(不含真实密钥)

git状态与最近提交注入

git 状态告诉 Agent"最近在改什么",避免重复劳动:

importsubprocessdefinject_git_status(root:Path)->str:"""注入 git 状态和最近提交"""parts=[]# git statustry:status=subprocess.run(["git","status","--short"],cwd=root,capture_output=True,text=True,timeout=5,)ifstatus.returncode==0andstatus.stdout.strip():parts.append(f"### Git 状态(未提交的改动)\n```\n{status.stdout.strip()}\n```")exceptException:pass# 最近提交try:log=subprocess.run(["git","log","--oneline","-5"],cwd=root,capture_output=True,text=True,timeout=5,)iflog.returncode==0andlog.stdout.strip():parts.append(f"### 最近提交\n```\n{log.stdout.strip()}\n```")exceptException:passreturn"\n\n".join(parts)

git 状态的价值:如果 Agent 看到"已经有 3 个文件被修改,正在改登录功能",它就会接着这个思路往下做,而不是另起炉灶。

完整实现:context_inject.py

整合成完整模块,拼装成一段"环境上下文":

# deep_pilot/context_inject.py —— 完整版from__future__importannotationsimportsubprocessfrompathlibimportPathfromdeep_pilot.loggerimportget_logger logger=get_logger(__name__)IGNORE_DIRS={".git","node_modules",".venv","__pycache__","dist","build",".pytest_cache",".tox"}IGNORE_FILES={".pyc",".pyo",".so",".dll",".exe"}defgenerate_tree(root:Path,max_depth:int=3,max_files:int=200)->str:root=Path(root).resolve()lines=[]file_count=0defwalk(dir_path:Path,prefix:str,depth:int):nonlocalfile_countifdepth>max_depth:lines.append(f"{prefix}...(深度超限)")returnentries=sorted(dir_path.iterdir(),key=lambdap:(p.is_file(),p.name))forentryinentries:ifentry.nameinIGNORE_DIRS:continueifentry.is_file()andentry.suffixinIGNORE_FILES:continueiffile_count>=max_files:lines.append(f"{prefix}...(文件数超限)")returnifentry.is_dir():lines.append(f"{prefix}├──{entry.name}/")walk(entry,prefix+"│ ",depth+1)else:lines.append(f"{prefix}├──{entry.name}")file_count+=1lines.append(f"{root.name}/")walk(root,"",1)return"\n".join(lines)definject_important_files(root:Path)->str:parts=[]forfnamein["README.md","pyproject.toml",".env.example"]:fpath=root/fnameiffpath.exists():content=fpath.read_text(encoding="utf-8",errors="ignore")iflen(content)>1000:content=content[:1000]+"\n...[已截断]"parts.append(f"###{fname}\n```\n{content}\n```")return"\n\n".join(parts)definject_git_status(root:Path)->str:parts=[]try:status=subprocess.run(["git","status","--short"],cwd=root,capture_output=True,text=True,timeout=5)ifstatus.returncode==0andstatus.stdout.strip():parts.append(f"### Git 状态\n```\n{status.stdout.strip()}\n```")exceptException:passtry:log=subprocess.run(["git","log","--oneline","-5"],cwd=root,capture_output=True,text=True,timeout=5)iflog.returncode==0andlog.stdout.strip():parts.append(f"### 最近提交\n```\n{log.stdout.strip()}\n```")exceptException:passreturn"\n\n".join(parts)defbuild_environment_context(root:Path|str=".")->str:"""构建完整的环境上下文,用于注入 system prompt 或首条消息"""root=Path(root).resolve()sections=[]tree=generate_tree(root)sections.append(f"## 项目结构\n```\n{tree}\n```")important=inject_important_files(root)ifimportant:sections.append(f"## 重要文件\n{important}")git_info=inject_git_status(root)ifgit_info:sections.append(git_info)return"\n\n".join(sections)

实测:Agent 一启动就懂项目

uv run python-c" from deep_pilot.context_inject import build_environment_context env_ctx = build_environment_context('.') print(env_ctx[:800]) print('...') print(f'环境上下文总长度: {len(env_ctx)} 字符') "

控制台输出(精简):

## 项目结构

deep-pilot/
├── deep_pilot/
│ ├──init.py
│ ├── agent_loop.py
│ ├── client.py
│ ├── config.py
│ ├── file_tools.py
│ ├── …
├── tests/
├── pyproject.toml
├── README.md

## 重要文件 ### pyproject.toml

[project]
name = “deep-pilot”
dependencies = [“openai”, “pydantic”, …]

... 环境上下文总长度: 2847 字符

Agent 一启动就"看见"了项目结构、依赖、README,不用瞎猜。实际使用时,把这段环境上下文注入到 system prompt 或首条 user 消息里:

# agent_loop.py 里env_ctx=build_environment_context(".")messages=[{"role":"system","content":f"你是 DeepPilot 编程助手。\n\n当前项目环境:\n{env_ctx}"},{"role":"user","content":user_query},]

小结

  1. 环境感知是效率关键:注入项目结构让 Agent 少做无用功,一启动就懂项目。
  2. 文件树生成三控:max_depth 限深度、max_files 限数量、IGNORE_DIRS 跳过无关目录。
  3. 重要文件注入:README(项目是什么)、pyproject(技术栈)、.env.example(环境变量)。
  4. git 状态注入:告诉 Agent"最近在改什么",避免重复劳动、接着思路做。
  5. token 可控:文件树约 800-1500 token,重要文件限 1000 字符,整体几千字符可接受。
  6. 注入到 system prompt:环境上下文放 system,Agent 全程可见。
  7. DeepPilot v0.6 文件树注入完成——Agent 从"瞎子摸象"到"一眼看全",效率大幅提升。

下节预告

注入了项目结构,Agent"看见"了。但还有个更根本的问题——系统提示词怎么写。system prompt 是 Agent 的灵魂,决定了它的行为方式。下一节做系统提示词工程:把 DeepPilot 的系统提示词逐段拆解(角色定义/工具规范/安全约束/输出格式),再讲版本管理和回归测试。


如果觉得本文对你有帮助,欢迎点赞、收藏、关注三连!
本系列持续更新中,关注不迷路~

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询