Agent Framework 1.22: AsIChatClient позволяет AIAgent выступить в роли IChatClient
Microsoft Agent Framework .NET 1.22.0 добавляет AIAgent.AsIChatClient() и замыкает круг, начатый IChatClient.AsAIAgent(). Агент сохраняет инструкции и инструменты и теперь подходит любому API, который принимает IChatClient.
Microsoft Agent Framework dotnet-1.22.0 вышел 2026-09-18, и внимания в нём заслуживает PR #7687: AsIChatClient. В Microsoft.Extensions.AI уже давно есть ChatClientExtensions.AsAIAgent(), превращающий чат-клиент в агента. Обратного направления не было. Теперь оно появилось, и круг замкнулся.
Чем было плохо отсутствие обратного направления
Список API .NET, принимающих IChatClient, продолжает расти: оценщики из Microsoft.Extensions.AI.Evaluation, middleware кеширования и телеметрии, всё, что построено на конвейере ChatClientBuilder. AIAgent — объект более богатый. Он несёт инструкции, набор инструментов, сессию и все обёртки middleware, которые вы вокруг него выстроили. Передавая такому API голый IChatClient, всё это приходилось собирать заново вручную либо отдавать оценщику-судье модель без того системного промпта, который и делает её судьёй.
AsIChatClient находится в Microsoft.Agents.AI и выглядит так:
public static IChatClient AsIChatClient(
this AIAgent agent,
AgentSession? session = null,
string? conversationId = null,
bool allowNonChatClientAgents = false)
Агент-судья превращается в чат-клиент-судью одним вызовом:
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
AIAgent judge = chatClient.CreateAIAgent(
instructions: "You score answers for factual accuracy. Reply with JSON only.",
name: "Judge");
IChatClient judgeClient = judge.AsIChatClient();
Адаптером служит внутренний AIAgentChatClient, который отображает GetResponseAsync и GetStreamingResponseAsync на RunAsync и RunStreamingAsync и передаёт ваши ChatOptions дальше как ChatClientAgentRunOptions. Отмена операции проходит насквозь, а GetService<IChatClient>() без ключа возвращает адаптер, тогда как любой другой запрос сервиса переадресуется агенту.
Проверка на входе и когда её отключать
По умолчанию вызов бросает InvalidOperationException, если только агент не является ChatClientAgent или не возвращает такой из GetService<ChatClientAgent>() без ключа. Декораторы на основе DelegatingAIAgent этот запрос переадресуют, поэтому обёрнутый агент проверку проходит.
Укажите allowNonChatClientAgents: true, и обёрнут будет агент любого типа, но мелкий шрифт читать обязательно: переход переживает только ChatOptions.ResponseFormat. Температура, инструменты и всё остальное молча игнорируются, потому что у агента-workflow или удалённого агента A2A нет опций чата, к которым их можно было бы применить.
Второе острое место — сессии. В режиме без состояния, который включён по умолчанию, непустой ChatOptions.ConversationId приводит к исключению, а исходные идентификаторы ответов очищаются в возвращаемых копиях. Передайте session, и клиент будет сообщать один и тот же стабильный идентификатор беседы для каждого ответа: переданный вами либо сгенерированный для этого экземпляра. Идентификатор со стороны сервиса он не раскрывает никогда, благодаря чему состояние беседы у провайдера остаётся внутри сессии, где ему и место. Любой другой непустой идентификатор отвергается как неизвестный.
API помечен атрибутом [Experimental], так что до подавления соответствующей диагностики сборка будет падать с ошибкой.
Ещё одна строка того же релиза стоит поиска по вашему коду: PR #8531 теперь передаёт инструменты ChatClientAgent на каждый запуск, а не выставляет их на нижележащем чат-клиенте с вызовом функций, из-за чего инструменты больше не дублируются и не утекают между агентами, использующими общий клиент. Это изменение помечено как BREAKING, как и перенос AgentSessionStore в Microsoft.Agents.AI.Abstractions.
Обновитесь до Microsoft.Agents.AI 1.22.0, а если вы пропустили релиз прошлой недели, сначала посмотрите, что версия 1.21 изменила в LocalCodeAct и окружении вашего хоста.
Comments
Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.