将你自己的 Agent 接入 MS Teams
摘要
微软全新的 Teams TypeScript SDK 让开发者只需三行 HTTP 服务器适配代码,就能把现有 AI Agent 或机器人暴露为 Teams 应用,实现 Slack 与 Teams 共用一套 Agent 逻辑。
暂无内容
查看缓存全文
缓存时间: 2026/04/22 23:53
# 把你的 Agent 带到 Teams
来源:https://microsoft.github.io/teams-sdk/blog/bring-your-agent-to-teams/
你已经有了 Agent,它跑在某个地方:一条 LangChain 链、一个 Azure Foundry 部署、一个 Slack bot……而你的用户在 Teams。
Teams 才是企业真正干活的地方:决策、客户响应、项目推进都在这儿。
在还没写任何 Teams 专属代码前,先把 Agent 接进来就已经值回票价。
关键就是 Teams TypeScript SDK 里的一个模式:**HTTP server adapter**。
把它指向你的 HTTP 服务,注册一条消息端点,原来的服务一行不改继续跑。
下面三种起步场景:Slack bot、LangChain 链、Azure Foundry Agent,都用同一套三步模板:
```ts
import { App as TeamsApp, ExpressAdapter } from '@microsoft/teams.apps';
const adapter = new ExpressAdapter(expressApp); // 1. 包裹你的服务
const teamsApp = new TeamsApp({ httpServerAdapter: adapter }); // 2. 创建 Teams 应用
teamsApp.on('message', async ({ send, activity }) => { // 3. 处理消息
await send(/* 你的 Agent 回复 */);
});
await teamsApp.initialize(); // 在你的服务上注册 POST /api/messages
```
SDK 会自动在现有 Express 应用里注入 `POST /api/messages`——Teams 给 bot 发消息的“标准接口”。
服务还是你的,Teams SDK 只加这一条路由。
---
### 场景 1:已有 Slack bot(Bolt)
团队同时用 Slack 和 Teams,不想维护两套代码。
`ExpressReceiver` 让 Bolt 挂在你的 Express 上,Teams SDK 同理,双平台共享同一个进程。
**slack-app.ts**:原 Slack 逻辑不动
```ts
import { App as BoltApp, ExpressReceiver } from '@slack/bolt';
import type { Express } from 'express';
export function mountSlack(expressApp: Express) {
const slackReceiver = new ExpressReceiver({
signingSecret: process.env.SLACK_SIGNING_SECRET,
app: expressApp,
endpoints: { events: '/slack/events' },
});
const slackApp = new BoltApp({
token: process.env.SLACK_BOT_TOKEN,
receiver: slackReceiver,
});
slackApp.message('hello', async ({ say }) => {
await say('Hey! Caught you on Slack.');
});
}
```
**teams-app.ts**:
```ts
import express from 'express';
import { App as TeamsApp, ExpressAdapter } from '@microsoft/teams.apps';
import { mountSlack } from './slack-app';
const expressApp = express();
mountSlack(expressApp);
const adapter = new ExpressAdapter(expressApp);
const teamsApp = new TeamsApp({ httpServerAdapter: adapter });
teamsApp.on('message', async ({ send, activity }) => {
await send(`Hey ${activity.from.name}! You said: "${activity.text}"`);
});
export { expressApp, teamsApp };
```
Slack 走 `/slack/events`,Teams 走 `/api/messages`,共用 LLM、数据库、业务函数。
---
### 场景 2:已有 LangChain 链
**chain.ts**:原链不动
```ts
import { ChatOpenAI } from '@langchain/openai';
import { ChatPromptTemplate } from '@langchain/core/prompts';
import { StringOutputParser } from '@langchain/core/output_parsers';
let _chain: ReturnType<typeof buildChain> | null = null;
function buildChain() {
const prompt = ChatPromptTemplate.fromMessages([
['system', 'You are a helpful assistant embedded in Microsoft Teams. Be concise.'],
['human', '{input}'],
]);
return prompt.pipe(new ChatOpenAI({ model: 'gpt-4o-mini' })).pipe(new StringOutputParser());
}
export function getChain() {
if (!_chain) _chain = buildChain();
return _chain;
}
```
**teams-app.ts**(桥梁):
```ts
import express from 'express';
import { App as TeamsApp, ExpressAdapter } from '@microsoft/teams.apps';
import { getChain } from './chain';
const expressApp = express();
const adapter = new ExpressAdapter(expressApp);
const teamsApp = new TeamsApp({ httpServerAdapter: adapter });
teamsApp.on('message', async ({ send, activity }) => {
await send({ type: 'typing' });
const reply = await getChain().invoke({ input: activity.text ?? '' });
await send(reply);
});
export { expressApp, teamsApp };
```
**index.ts**(启动):
```ts
import 'dotenv/config';
import http from 'http';
import { expressApp, teamsApp } from './teams-app';
await teamsApp.initialize();
http.createServer(expressApp).listen(3978);
```
每条消息触发链,先发送“正在输入”指示器,再返回 LLM 结果。
---
### 场景 3:已有 Azure AI Foundry Agent
**foundry-agent.ts**:
```ts
import { AIProjectClient } from '@azure/ai-projects';
import { DefaultAzureCredential } from '@azure/identity';
let _client: AIProjectClient | null = null;
function getClient() {
if (!_client) {
_client = AIProjectClient.fromEndpoint(
process.env.AZURE_AI_FOUNDRY_ENDPOINT!,
new DefaultAzureCredential(),
);
}
return _client;
}
export async function askFoundryAgent(userMessage: string): Promise<string> {
const client = getClient();
const thread = await client.agents.threads.create();
await client.agents.messages.create(thread.id, 'user', userMessage);
const run = await client.agents.runs.createAndPoll(thread.id, process.env.AZURE_AGENT_ID!);
if (run.status !== 'completed') throw new Error(`Run ended: ${run.status}`);
const messages = client.agents.messages.list(thread.id);
for await (const msg of messages) {
if (msg.role === 'assistant') {
return msg.content
.filter((c): c is { type: 'text'; text: { value: string } } => c.type === 'text')
.map((c) => c.text.value)
.join('');
}
}
return 'No response from agent.';
}
```
**teams-app.ts**:
```ts
import express from 'express';
import { App as TeamsApp, ExpressAdapter } from '@microsoft/teams.apps';
import { askFoundryAgent } from './foundry-agent';
const expressApp = express();
const adapter = new ExpressAdapter(expressApp);
const teamsApp = new TeamsApp({ httpServerAdapter: adapter });
teamsApp.on('message', async ({ send, activity }) => {
const reply = await askFoundryAgent(activity.text ?? '');
await send(reply);
});
export { expressApp, teamsApp };
```
---
### Python SDK 也一样
```python
from fastapi import FastAPI
from microsoft_teams.apps import App, FastAPIAdapter
fastapi_app = FastAPI()
adapter = FastAPIAdapter(app=fastapi_app) # 1. 包裹
teams_app = App(http_server_adapter=adapter) # 2. 创建
@teams_app.on_message
async def handle_message(ctx): # 3. 处理
await ctx.send("your agent's response")
await teams_app.initialize()
```
完整 Python 指南见 [Self-Managing Your Server](https://microsoft.github.io/teams-sdk/python/in-depth-guides/server/http-server)。
---
### 三步上线
1. 给本地服务一个公网 HTTPS 地址
推荐 [Dev tunnels](https://learn.microsoft.com/en-us/azure/developer/dev-tunnels/overview),VS Code / Azure CLI 内置;也可用 ngrok。
拿到类似 `https://abc123.devtunnels.ms` 的地址。
2. 用 Teams SDK CLI 注册 bot
```bash
npm install -g @microsoft/teams.cli@preview
teams login
teams app create --name "My Bot" --endpoint https://your-tunnel-url/api/messages --env .env
```
一条命令完成 AAD 注册、秘钥、manifest、bot 创建,`.env` 自动写入 `CLIENT_ID`、`CLIENT_SECRET`、`TENANT_ID`。
3. 侧载到 Teams
CLI 输出里有指引,按步骤把应用装到 Teams 客户端即可测试。
---
所有例子都遵循同一思想:**你的服务器你做主**。
Adapter 只是现有基础设施与 Teams 之间的接缝。
Express 或其他 HTTP 框架均可,SDK 只要求能注册路由、处理请求。
```ts
const adapter = new (yourServer); // ExpressAdapter 或自定义
const teamsApp = new TeamsApp({ httpServerAdapter: adapter });
teamsApp.on('message', async ({ send, activity }) => { /* 你的 Agent */ });
```
已有 bot?几行胶水就能进 Teams。
完整文档见 [Self-Managing Your Server](https://microsoft.github.io/teams-sdk/typescript/in-depth-guides/server/http-server/)。
相似文章
@svpino: 以下是如何通过 Slack、Teams、Discord、WhatsApp 或 Telegram 构建并分发你的 Agent。这是给那些…
一位开发者布道师展示了如何使用 CopilotKit 的 Channels SDK 将 AI Agent 分发到 Slack、Teams、Discord、WhatsApp 和 Telegram,该 SDK 负责处理各平台特定的集成和原生 UI 渲染。
Show HN: Channels SDK – 将任意智能体接入任意渠道(Slack、MS Teams)
CopilotKit 宣布推出 Channels SDK,这是一个开源工具包,让开发者能够将任何兼容 AG-UI 的 AI 智能体连接到 Slack、Microsoft Teams 和 Discord,并支持原生交互式界面、工具调用和人工审批门控。
Channels SDK
Channels SDK 使开发者能够将 AI 代理部署到 Slack 和 Teams,而无需面对常见的生产环境痛点。
每次他们发布AI代理时,你都得重建Slack或Teams集成层吗?
一位开发者讨论了在Slack和Microsoft Teams中集成AI代理的持续挑战,指出尽管LangGraph和CrewAI等代理逻辑工具有所改进,但集成层(包括线程上下文、认证、流式传输、权限)常常需要重建。
Agent 设计用于共享,但现有工具并不适用
作者讨论了跨团队共享 AI Agent 工作流的困难,并介绍了 Nairi,这是一款用于在 Slack 中部署基于 Claude Code 的 Agent 且支持共享访问的工具。