目标效果:
钉钉群里发:
create php file User.php
↓
服务器收到消息
↓
调用 AI 生成代码
↓
写入文件 + git commit
↓
钉钉返回执行结果下面给你一个 Node.js 可直接跑的版本。
一、在钉钉创建机器人
1️⃣ 打开钉钉群
2️⃣ 群设置 → 机器人 → 添加机器人
3️⃣ 选择 自定义机器人
你会得到:
- Webhook URL
- 加签密钥(secret)
保存这两个。
二、Mac mini 上创建项目
mkdir ding-ai-bot
cd ding-ai-bot
npm init -y
npm install express axios crypto body-parser simple-git三、完整服务器代码(server.js)
这个版本包含:
- 接收钉钉消息
- 校验签名
- 调用 AI(示例用 Claude API)
- 写文件
- git commit
- 回复钉钉
const express = require('express')
const crypto = require('crypto')
const axios = require('axios')
const bodyParser = require('body-parser')
const fs = require('fs')
const simpleGit = require('simple-git')
const app = express()
app.use(bodyParser.json())
const PORT = 3000
// 你的钉钉 secret
const DING_SECRET = '你的加签secret'
const DING_WEBHOOK = '你的Webhook地址'
// Claude API
const CLAUDE_API_KEY = process.env.ANTHROPIC_API_KEY
// git 实例
const git = simpleGit()
// ====== 验证钉钉签名 ======
function verifySign(timestamp, sign) {
const stringToSign = `${timestamp}\n${DING_SECRET}`
const hmac = crypto.createHmac('sha256', DING_SECRET)
hmac.update(stringToSign)
const calcSign = hmac.digest('base64')
return calcSign === sign
}
// ====== 调用 Claude 生成代码 ======
async function callClaude(prompt) {
const res = await axios.post(
'https://api.anthropic.com/v1/messages',
{
model: "claude-3-sonnet-20240229",
max_tokens: 800,
messages: [
{ role: "user", content: prompt }
]
},
{
headers: {
'x-api-key': CLAUDE_API_KEY,
'anthropic-version': '2023-06-01',
'Content-Type': 'application/json'
}
}
)
return res.data.content[0].text
}
// ====== 发送消息到钉钉 ======
async function replyDingTalk(text) {
await axios.post(DING_WEBHOOK, {
msgtype: "text",
text: {
content: text
}
})
}
// ====== 主处理逻辑 ======
app.post('/ding', async (req, res) => {
const { timestamp, sign } = req.query
if (!verifySign(timestamp, sign)) {
return res.status(403).send('sign error')
}
const msg = req.body.text?.content
if (!msg) {
return res.send('ok')
}
try {
// 示例命令:create php file User.php
if (msg.startsWith('create php file')) {
const fileName = msg.split(' ')[3]
const prompt = `生成一个 ${fileName} PHP 类,包含基础CRUD结构`
const code = await callClaude(prompt)
fs.writeFileSync(`./workspace/${fileName}`, code)
await git.add(`./workspace/${fileName}`)
await git.commit(`feat: add ${fileName}`)
await replyDingTalk(`✅ 已生成 ${fileName} 并提交 Git`)
}
else {
await replyDingTalk('未知命令')
}
res.send('ok')
} catch (err) {
console.error(err)
await replyDingTalk('❌ 执行失败')
res.send('error')
}
})
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`)
})四、创建 workspace 目录
mkdir workspace并初始化 git:
cd workspace
git init五、启动服务
export ANTHROPIC_API_KEY=你的key
node server.js建议用 pm2:
npm install -g pm2
pm2 start server.js --name ding-ai
pm2 save六、让钉钉访问到你的 Mac mini
如果在内网,需要:
- 用云服务器反向代理
- 或用 frp
- 或 ngrok
钉钉 webhook 地址要能公网访问:
https://你的域名/ding七、测试流程
在钉钉群发:
create php file User.php如果成功:
- workspace/User.php 被创建
- git commit 自动完成
- 群里收到成功消息
八、安全优化(必须做)
1️⃣ 限制只处理 @机器人 消息
2️⃣ 限制用户ID
3️⃣ 限制可操作目录
4️⃣ 禁止执行任意 shell
5️⃣ 限制 token 消耗
否则可能被恶意触发大量 API 费用。
九、如何接入 OpenClaw
如果你想用 OpenClaw 做执行层:
把:
callClaude(prompt)替换成:
调用 OpenClaw API即可。
架构变为:
钉钉 → 你的服务器 → OpenClaw → Claude → 执行 → 返回十、成本控制建议
推荐模型:
- claude-3-haiku(省钱)
- claude-3-sonnet(平衡)
不要默认用 Opus。
最终效果
你现在拥有:
一个国内可用的远程 AI 程序员
通过钉钉控制:
- 写代码
- 提交 Git
- 修改文件
- 运行脚本
全部远程完成。