进入主要内容

面向你的人工智能的 Azure DevOps API


你的 AI 助手会读代码,但它看不到 Azure DevOps 仓库里沉睡着的东西。这个 API 搭起了桥梁:项目、文件、提交、拉取请求,全部用简单的 JSON 呈现,并使用你自己的访问权限。

先把话说清楚:我一开始就是为机器设计它的。一个 AI agent、一个 MCP 服务器(这个协议能让 Claude 这样的助手调用外部工具)或者一个简单脚本。人类当然也欢迎,但我的想法是,让 AI 可以请求“给我看看这个文件”或者“这个提交改了什么”,而不必猜 Azure DevOps 的 API 是怎么工作的,因为它很强大,但说真的,实在太复杂了。

这是这个服务的 Swagger 页面,所有调用都列在这里:

Digital3D Azure DevOps API 的 Swagger 页面,包含 Health、WhoAmI、Projects 和 Repos 路由

免费版或 PRO:你能得到什么

两种方案都能访问相同的调用,包括写入操作。唯一的区别,就是每天的请求数量。绿色进度条显示你一天可以发起多少请求。

免费 API

0 €,你的账户密钥就够了

10每天
  • 每天 10 个请求
  • 所有调用,包括读取和写入
  • 单个请求最多读取 50 个文件
  • 足够你接入一个 agent,看看它是否理解你的代码

PRO API

每月 12 €,我所有的软件都包括在内

每天 1000 个
  • 每天 1000 个请求
  • 足够一个 agent 在你的仓库上工作一整天
  • 11 天的完整电视指南,外加我的软件
  • 下一次请求立即生效,使用同一个密钥

升级到 PRO

计数器会在 UTC 午夜归零,所以在法国是凌晨 1 点或 2 点,具体取决于季节。一个话多的 agent 很快就能用光十个请求。我的建议是这样让它们撑久一点:files:batch 调用可以带回最多 50 个文件,而且只算一个请求。

这个 API 会做什么

大约二十个调用,全部位于 https://devops.digital3d.com/api/Devops/ 下。我是按需求而不是按字母顺序整理它们的:

需求调用返回内容
定位Projects, Repos, Repos/{repoId}组织的项目、Git 仓库(全部仓库,或某个项目的仓库),以及包含默认分支的仓库详情。
浏览代码tree, files, search某个文件夹的目录树、某个分支中的所有文件列表,或按类似 **/*.cs 的模式进行搜索。
读取文件file, fileAt, files:batch某个分支或特定提交中的文件原始内容,或一次获取最多 50 个文件。
跟踪历史branches, tags, commits, pushes分支、标签、提交日志(可按路径和分支筛选)、某次提交的详情及其修改文件列表。
比较diffs/commits两个提交之间的差异,默认以紧凑摘要形式显示,也可以显示完整版本。
审查拉取请求pullrequests活跃、已完成或已放弃的合并请求,以及其中某个请求的详情。
写入write创建或修改文件,并作为只包含一次提交的 push 交付。

还有两个服务调用:Health,无需密钥即可响应,而且永远不会计数,以及 WhoAmI,它会确认您的请求头是否被正确理解。

要发送的三个请求头

每个请求都带有三个请求头。一个给我,两个给 Azure DevOps。

请求头您要填入的内容用途
AuthorizationBearer VotreCleApi您的 Digital3D 密钥。配额由它承载。
X-Ado-Org您的组织名称告诉 API 要查询哪个 Azure DevOps 组织。
X-Ado-Pat您的个人访问令牌以您的名义调用 Azure DevOps,使用您的权限,不多不少。

Digital3D 密钥。 创建账户,验证您的电子邮件地址,然后复制显示在您的账户中的密钥。这和我其他服务使用的是同一个密钥。如果您使用的是旧版本,请注意:请求头 X-Api-Key 已被 Authorization 取代。

组织名称。 登录 https://dev.azure.com 并查看地址。在 https://dev.azure.com/ma-societe/ 中,要发送的值是 ma-societe。这是组织名称,不是项目名称。

个人访问令牌(PAT,一种权限受限的密码)。在 Azure DevOps 中,点击右上角的用户设置图标,然后点击 “Personal access tokens” 和 “New Token”。给它起一个有意义的名称,设置较短的有效期(30 或 90 天),并且只授予有用的权限:要读取全部内容,“Code (Read)” 和 “Project and Team (Read)” 就够了。只有在您的代理需要写入时,才添加 “Code (Read & Write)”。立即复制令牌,Azure DevOps 只会显示它一次。

提醒一句,因为这是您的代码:这个令牌可以访问您的代码仓库,并且每次请求都会经过我的服务器。只授予它最低限度的权限,设置过期日期,在您不再需要它的那天撤销它。换作是我,我也会这么做。

第一次调用

先确认三个请求头都能通过:

curl "https://devops.digital3d.com/api/Devops/WhoAmI" \
  -H "Authorization: Bearer VotreCleApi" \
  -H "X-Ado-Org: ma-societe" \
  -H "X-Ado-Pat: VotreJetonAzure"

然后是仓库列表。每个仓库都有一个标识符(GUID),所有其他调用都需要用它来替代 {repoId}:

curl "https://devops.digital3d.com/api/Devops/Repos?project=MonProjet" \
  -H "Authorization: Bearer VotreCleApi" \
  -H "X-Ado-Org: ma-societe" \
  -H "X-Ado-Pat: VotreJetonAzure"

要在一个仓库的默认分支上查找所有 C# 文件:

curl "https://devops.digital3d.com/api/Devops/Repos/{repoId}/search?glob=**/*.cs" \
  -H "Authorization: Bearer VotreCleApi" \
  -H "X-Ado-Org: ma-societe" \
  -H "X-Ado-Pat: VotreJetonAzure"

要在一次请求中读取多个文件,使用 POST,并附上路径列表:

curl -X POST "https://devops.digital3d.com/api/Devops/Repos/{repoId}/files:batch" \
  -H "Authorization: Bearer VotreCleApi" \
  -H "X-Ado-Org: ma-societe" \
  -H "X-Ado-Pat: VotreJetonAzure" \
  -H "Content-Type: application/json" \
  -d '{ "paths": ["/README.md", "/src/Program.cs"], "refName": "main" }'

凡是需要分支的地方(refName),你都可以写 main,或者写完整形式 refs/heads/main。如果什么都不填,就会采用仓库的默认分支。

比较和写入

到这里,对于一个代理来说就真的有意思了。要知道两个提交之间有什么差异:

curl -X POST "https://devops.digital3d.com/api/Devops/Repos/{repoId}/diffs/commits" \
  -H "Authorization: Bearer VotreCleApi" \
  -H "X-Ado-Org: ma-societe" \
  -H "X-Ado-Pat: VotreJetonAzure" \
  -H "Content-Type: application/json" \
  -d '{ "baseCommit": "abc123", "targetCommit": "def456", "summaryOnly": true }'

当 summaryOnly 为 true 时(默认值),响应就是一份紧凑的摘要:修改过的文件总数和路径。这样设计是有道理的。AI 读到的每个字都要付钱,所以当一份摘要已经够用时,就没必要把 Azure DevOps 的原始响应端给它。

还有,写入文件:

curl -X POST "https://devops.digital3d.com/api/Devops/Repos/{repoId}/write" \
  -H "Authorization: Bearer VotreCleApi" \
  -H "X-Ado-Org: ma-societe" \
  -H "X-Ado-Pat: VotreJetonAzure" \
  -H "Content-Type: application/json" \
  -d '{
    "path": "/docs/notes.md",
    "content": "# Notes\n\nEcrit par mon agent.",
    "branch": "feature/notes",
    "createBranch": true,
    "commitMessage": "Ajout des notes"
  }'

好吧,认真两分钟:让 AI 写入代码仓库,这事得加上护栏才行。为此有三个设置。createBranch 会在分支不存在时创建它,这样就能让代理在一旁工作,再通过 pull request 检查它的成果。expectHeadCommit 会声明代理看到的最后一个提交:如果期间有人推送过内容,写入就会被拒绝,而不是覆盖对方的工作。服务器端还会限制写入文件的大小。如果你根本不想允许写入,最安全的做法还是使用只读令牌:Azure DevOps 会自行拒绝写入。

底层原理

这里有一些解释 API 行为的技术选择。

每次请求都由你指定要查询哪个组织,以及使用哪个令牌。因此,同一个 API 可以服务于任何 Azure DevOps 组织,而且它看到的内容不会超出你的令牌所授权的范围。

Digital3D 密钥会先经过验证。只要密钥被接受,就会计为一次请求,不管 Azure DevOps 之后返回什么。组织名称错误或令牌过期也会消耗一次请求:所以最好先用 WhoAmI 一次性验证配置,而不是在那里反复试。

两个 401 错误看起来很像,原因却不一样。带有 WWW-Authenticate: Bearer 请求头的那个来自我这边:Digital3D 密钥缺失或被拒绝,不会计入任何请求。没有这个请求头的那个来自 Azure DevOps:检查一下 X-Ado-Org 和 X-Ado-Pat。

返回结果都有上限,以免太难消化:批量读取时最多 50 个文件,约 2 MB,文件列表默认最多 2000 个条目,日志默认最多 50 个提交。这些上限可以通过 top 和 maxItems 参数进行调整。

跟踪你的配额

密钥一旦通过,每个响应都会带有三个标头:X-RateLimit-Limit(你当天的限额)、X-RateLimit-Remaining(你还剩多少)和 X-RateLimit-Reset(重置时间,以 Unix 秒数表示)。一个懂礼貌的代理会读取 X-RateLimit-Remaining,在撞墙之前先放慢脚步。

  • 429:当天的配额用完了。Retry-After标头会告诉你在重置前需要等待多少秒。
  • 503:服务无法验证密钥。30 秒后再试一次。
  • 其他错误会返回一个 JSON 对象,其中有一个error字段,说明出了什么问题。

无需写一行代码就能测试

所有内容都记录在API 的 Swagger 文档中。点击“Authorize”,填写三个字段(密钥、组织、令牌),然后用“Try it out”按钮逐个尝试调用。不过要注意:这些尝试也会计入你的配额,就像任何请求一样。同一个 Swagger 也可以作为 AI 的契约:把文件地址 https://devops.digital3d.com/swagger/v1/swagger.json给它,它就会自己发现这些调用。

为什么要订阅?

因为这一切都运行在一台由我付费的服务器上。免费服务会保留,用来测试和进行轻量使用。如果代理每天都在处理你的代码仓库,每月 12 € 的 PRO 订阅会把限额提高到每天 1000 个请求,包含完整的 TV 指南和我的所有软件,而这正是让服务继续运行下去的东西。未订阅不得用于商业用途。如果你需要更多,给我写信。

加入对话

您必须拥有一个账户才能评论这篇文章。注册免费,耗时不到一分钟。

  • 每天免费下载的 XMLTV 文件
  • 评论文章并回复其他读者
  • 通过电子邮件获知您关注的新文章

目前没有评论。

Une erreur s'est produite. Cette application peut ne plus répondre jusqu'à ce qu'elle soit rechargée.Veuillez contacter l'auteur. Reload 🗙