news 2026/4/24 22:15:46

C# 实现简版 Claude Code | 4 个工具覆盖 90% 场景(2)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C# 实现简版 Claude Code | 4 个工具覆盖 90% 场景(2)

该系列文章基于github.com/shareAI-lab/learn-claude-code写就,该仓库以大道至简的风格剖析了Claude Code的核心原理,值得大家学习。由于该仓库是基于Python语言,为方便.NET开发者学习,我已经将代码基于.NET 10的dotnet file重写,源码已上传至github,源码地址见文末。

v1: 模型即代理 - 4 个工具覆盖 90% 场景

本文是 Learn Claude Code (C# 版) 系列的第二篇,对应代码文件v1_basic_agent.cs

从 v0 到 v1

v0 用一个 bash 工具证明了最简可行性。但在实际使用中:

  • cat读文件需要额外的 tokens 来构造命令

  • echo写文件容易出错(引号转义、换行处理)

  • 缺乏安全检查,可能逃逸工作目录

v1 引入4 个专用工具,这是 Claude Code 20+ 工具的精华提炼。

四个核心工具

工具

用途

覆盖场景

bash

运行任何命令

git, npm, dotnet, curl...

read_file

读取文件内容

理解代码

write_file

创建/覆盖文件

生成新文件

edit_file

精确文本替换

修改现有代码

为什么是这 4 个?因为编程任务本质上就是:探索 → 理解 → 修改 → 验证

工具定义详解

bash - 通往一切的大门

new Tool { Name = "bash", Description = "运行 shell 命令。用于: ls, find, grep, git, npm, dotnet 等。", InputSchema = new InputSchema { Type = "object", Properties = new Dictionary<string, JsonElement> { ["command"] = JsonDocument.Parse("""{"type": "string", "description": "要执行的命令"}""").RootElement }, Required = ["command"] } }

bash 仍然是最重要的工具——它是模型与外部世界交互的通道。

read_file - 理解现有代码

new Tool { Name = "read_file", Description = "读取文件内容。返回 UTF-8 文本。", InputSchema = new InputSchema { Type = "object", Properties = new Dictionary<string, JsonElement> { ["path"] = JsonDocument.Parse("""{"type": "string", "description": "文件的相对路径"}""").RootElement, ["limit"] = JsonDocument.Parse("""{"type": "integer", "description": "最大读取行数"}""").RootElement }, Required = ["path"] } }

limit参数很重要——大文件只需要看前 N 行,避免上下文溢出。

write_file - 创建新文件

new Tool { Name = "write_file", Description = "将内容写入文件。如果需要会创建父目录。", InputSchema = new InputSchema { Type = "object", Properties = new Dictionary<string, JsonElement> { ["path"] = JsonDocument.Parse("""{"type": "string"}""").RootElement, ["content"] = JsonDocument.Parse("""{"type": "string"}""").RootElement }, Required = ["path", "content"] } }

自动创建父目录是个贴心的设计——模型不需要先mkdir -p

edit_file - 精确修改

new Tool { Name = "edit_file", Description = "替换文件中的精确文本。用于局部编辑。", InputSchema = new InputSchema { Type = "object", Properties = new Dictionary<string, JsonElement> { ["path"] = JsonDocument.Parse("""{"type": "string"}""").RootElement, ["old_text"] = JsonDocument.Parse("""{"type": "string", "description": "要查找的精确文本"}""").RootElement, ["new_text"] = JsonDocument.Parse("""{"type": "string", "description": "替换文本"}""").RootElement }, Required = ["path", "old_text", "new_text"] } }

精确文本匹配是关键——模型必须提供要替换的确切内容,这避免了意外修改。

安全机制

路径安全检查

string SafePath(string p) { var fullPath = Path.GetFullPath(Path.Combine(workDir, p)); if (!fullPath.StartsWith(workDir)) throw new InvalidOperationException($"路径逃逸工作区: {p}"); return fullPath; }

防止../../../etc/passwd这样的路径遍历攻击。

危险命令阻止

string[] dangerous = ["rm -rf /", "sudo", "shutdown", "reboot", "> /dev/"]; if (dangerous.Any(d => command.Contains(d))) return "Error: 危险命令已阻止";

基本的安全护栏,阻止显然危险的命令。

输出截断

return output[..Math.Min(output.Length, 50000)];

50KB 上限防止一个巨大的输出撑爆上下文。

超时控制

using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60)); await process.WaitForExitAsync(cts.Token);

60 秒超时防止命令挂起。

Agent 循环详解

async Task AgentLoopAsync(List<Message> messages) { while (true) { // 步骤 1: 调用模型 var response = await client.CreateMessageAsync( modelId, messages, new MessageParameters { System = systemPrompt, Tools = tools, MaxTokens = 8000 }); // 步骤 2: 收集工具调用并打印文本输出 var toolCalls = new List<ToolUseBlock>(); foreach (var block in response.Content) { if (block.Text is not null) Console.WriteLine(block.Text.Text); // 模型的思考 if (block.ToolUse is not null) toolCalls.Add(block.ToolUse); // 工具调用 } // 步骤 3: 如果没有工具调用,任务完成 if (response.StopReason != StopReason.ToolUse) { messages.Add(response.AsRequestMessage()); return; } // 步骤 4: 执行每个工具并收集结果 var results = new List<ContentBlock>(); foreach (var tc in toolCalls) { var output = await ExecuteToolAsync(tc.Name, tc.Input); results.Add(ContentBlock.CreateToolResult(tc.Id, output)); } // 步骤 5: 添加到对话并继续 messages.Add(response.AsRequestMessage()); messages.Add(new Message { Role = "user", Content = [.. results] }); } }

为什么工具结果是 "user" 消息?

Anthropic API 的设计:工具结果作为user角色的消息发送,包含tool_result类型的内容块。这维持了 user/assistant 的交替模式。

消息历史结构

[user] "创建一个 hello world 程序" [assistant] "我来创建..." + tool_use(write_file, {path: "hello.cs", content: "..."}) [user] tool_result(id, "Wrote 50 bytes to hello.cs") [assistant] "文件已创建。让我运行它..." + tool_use(bash, {command: "dotnet run hello.cs"}) [user] tool_result(id, "Hello, World!") [assistant] "程序运行成功,输出了 'Hello, World!'"

工具分发器

async Task<string> ExecuteToolAsync(string name, JsonElement args) { return name switch { "bash" => await RunBashAsync(args.GetProperty("command").GetString()!), "read_file" => RunRead( args.GetProperty("path").GetString()!, args.TryGetProperty("limit", outvar limit) ? limit.GetInt32() : null), "write_file" => RunWrite( args.GetProperty("path").GetString()!, args.GetProperty("content").GetString()!), "edit_file" => RunEdit( args.GetProperty("path").GetString()!, args.GetProperty("old_text").GetString()!, args.GetProperty("new_text").GetString()!), _ => $"Unknown tool: {name}" }; }

C# 的 switch expression 让分发器代码非常简洁。

关键洞察

1. 模型即代理

传统编程:程序员写逻辑,代码执行。 Agent 编程:程序员提供工具,模型决定逻辑

v1 的代码只做了两件事:

  1. 定义工具(模型能做什么)

  2. 运行循环(让模型持续决策)

2. 工具即接口

工具定义就是给模型的 API 文档:

  • Name- 函数名

  • Description- 函数说明

  • InputSchema- 参数类型

模型根据这些信息决定调用什么、传什么参数。

3. 上下文即记忆

messages列表就是 Agent 的记忆。它累积:

  • 用户的请求

  • 模型的思考和工具调用

  • 工具的执行结果

模型通过阅读历史来理解当前状态。

运行示例

Mini Claude Code v1 (C#) - /path/to/project 输入 'exit' 退出。 You: 创建一个计算斐波那契数列的函数 我来创建一个计算斐波那契数列的 C# 文件。 > write_file: {"path":"Fibonacci.cs","content":"..."} Wrote 450 bytes to Fibonacci.cs 文件已创建。让我运行测试一下: > bash: {"command":"dotnet run Fibonacci.cs"} 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 成功!Fibonacci.cs 已创建并测试通过。

从 v1 到 v2

v1 解决了工具效率问题,但对于复杂任务:

You: 重构 auth 模块、添加测试、更新文档

模型可能会:

  • 随机跳转任务

  • 忘记已完成的步骤

  • 中途失焦

v2 将引入TodoManager——让计划显式化,给模型一个"外部记忆"来追踪进度。

总结

v1 的哲学:

模型即代理。代码提供工具,模型做决策。

4 个工具覆盖了 90% 的编程场景。核心循环只有 30 行。这就是 Agent 的本质——简单到令人惊讶。

点击阅读原文,获取仓库地址:👇👇👇

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/24 9:15:16

python基于微信小程序的旅游服务助手 景点 酒店 旅游规划 可视化

文章目录 功能概述核心模块设计技术实现要点数据存储方案扩展优化方向 系统设计与实现的思路主要技术与实现手段源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01; 功能概述 Python开发的微信小程序旅游服务助手整合景点查询、酒店预订、旅…

作者头像 李华
网站建设 2026/4/23 16:13:20

主流AI视频生成商用方案选型评测:五大核心维度对比分析

引言&#xff1a;从技术热潮到商业落地的挑战2024年&#xff0c;AI视频生成技术正从令人惊叹的“技术演示”阶段&#xff0c;快速迈向规模化“商业应用”阶段。无论是电商卖家、内容创作者&#xff0c;还是企业市场部门&#xff0c;都看到了利用AI高效生产视频内容的巨大潜力。…

作者头像 李华
网站建设 2026/4/23 17:02:57

30.9MB全球国界与中国国界私藏版

为了便于全球或全国私有化地图的数据提取&#xff0c;我们基于公开的全球数据处理了一份方便我们自用的全球与全国国界数据。 我们暂且称该数据为“全球与全国国界私藏版”&#xff0c;如果该数据对你也有用&#xff0c;请从GIS资源库自助领取。 30.9MB全球与全国国界私藏版 …

作者头像 李华
网站建设 2026/4/20 14:00:21

计算机SSM毕设实战-基于SSM框架的中小学生阅读能力培养系统的设计与实现基于ssm的中小学生阅读能力培养系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/4/20 13:39:25

三大智能体开发平台详细对比:FastGPT、Dify和Coze(附教程)

目前&#xff0c;市面上涌现了众多基于 RAG&#xff08;检索增强生成&#xff09;的优秀产品&#xff0c;其中以FastGPT、Dify 和Coze 最具代表性&#xff0c;备受用户关注与推崇。每款工具都在特定场景中展现了独特的技术优势与适用价值&#xff0c;同时也存在一些局限性。 本…

作者头像 李华