-
Notifications
You must be signed in to change notification settings - Fork 19
Quickstart LangChain Agent #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # OpenAI Configuration | ||
| OPENAI_API_KEY= | ||
JesuTerraz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
309 changes: 309 additions & 0 deletions
309
nodejs/langchain/quickstart-before/AGENT-CODE-WALKTHROUGH.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,309 @@ | ||
| # Agent Code Walkthrough | ||
|
|
||
| Step-by-step walkthrough of the implementation in `src/agent.ts`. | ||
| This is a quickstart starting point for building a LangChain agent with the Microsoft 365 Agents SDK. | ||
|
|
||
| ## Overview | ||
|
|
||
| | Component | Purpose | | ||
| |-----------|---------| | ||
| | **LangChain** | Core AI orchestration framework | | ||
| | **Microsoft 365 Agents SDK** | Enterprise hosting and authentication integration | | ||
|
|
||
| ## File Structure and Organization | ||
|
|
||
| ``` | ||
| quickstart-before/ | ||
| ├── src/ | ||
| │ ├── agent.ts # Main agent implementation | ||
| │ ├── client.ts # LangChain client wrapper | ||
| │ └── index.ts # Express server entry point | ||
| ├── package.json # Dependencies and scripts | ||
| ├── tsconfig.json # TypeScript configuration | ||
| └── .env # Configuration (not committed) | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| --- | ||
|
|
||
| ## Step 1: Dependency Imports | ||
|
|
||
| ### agent.ts imports: | ||
| ```typescript | ||
| import { TurnState, AgentApplication, TurnContext } from '@microsoft/agents-hosting'; | ||
| import { ActivityTypes } from '@microsoft/agents-activity'; | ||
| ``` | ||
|
|
||
| ### client.ts imports: | ||
| ```typescript | ||
| import { createAgent, ReactAgent } from "langchain"; | ||
| import { ChatOpenAI } from "@langchain/openai"; | ||
| ``` | ||
|
|
||
| **What it does**: Brings in all the external libraries and tools the agent needs to work. | ||
|
|
||
| **Key Imports**: | ||
| - **@microsoft/agents-hosting**: Bot Framework integration for hosting and turn management | ||
| - **@microsoft/agents-activity**: Activity types for different message formats | ||
| - **langchain**: LangChain framework for building AI agents | ||
| - **@langchain/openai**: OpenAI chat model integration for LangChain | ||
|
|
||
| --- | ||
|
|
||
| ## Step 2: Agent Initialization | ||
|
|
||
| ```typescript | ||
| class MyAgent extends AgentApplication<TurnState> { | ||
| constructor() { | ||
| super(); | ||
|
|
||
| this.onActivity(ActivityTypes.Message, async (context: TurnContext, state: TurnState) => { | ||
| await this.handleAgentMessageActivity(context, state); | ||
| }); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| **What it does**: Creates the main AI agent and sets up its basic behavior. | ||
|
|
||
| **What happens**: | ||
| 1. **Extends AgentApplication**: Inherits Bot Framework hosting capabilities | ||
| 2. **Event Routing**: Registers a handler for incoming messages | ||
|
|
||
| --- | ||
|
|
||
| ## Step 3: Agent Creation | ||
|
|
||
| The agent client wrapper is defined in `client.ts`: | ||
|
|
||
| ```typescript | ||
| export async function getClient(): Promise<Client> { | ||
| // Create the model | ||
| const model = new ChatOpenAI({ | ||
| model: "gpt-4o-mini", | ||
| }); | ||
|
|
||
| // Create the agent | ||
| const agent = createAgent({ | ||
| model: model, | ||
| tools: [], | ||
| name: 'My Custom Agent', | ||
| }); | ||
|
|
||
| return new LangChainClient(agent); | ||
| } | ||
| ``` | ||
|
|
||
| **What it does**: Creates a LangChain React agent with an OpenAI model. | ||
|
|
||
| **What happens**: | ||
| 1. **Model Creation**: Initializes ChatOpenAI with the specified model (gpt-4o-mini) | ||
| 2. **Agent Creation**: Creates a React agent with the model and tools | ||
| 3. **Returns Client**: Wraps the agent in a client interface | ||
|
|
||
| --- | ||
|
|
||
| ## Step 4: Message Processing | ||
|
|
||
| ```typescript | ||
| async handleAgentMessageActivity(turnContext: TurnContext, state: TurnState): Promise<void> { | ||
| const userMessage = turnContext.activity.text?.trim() || ''; | ||
|
|
||
| if (!userMessage) { | ||
| await turnContext.sendActivity('Please send me a message and I\'ll help you!'); | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| const client: Client = await getClient(); | ||
| const response = await client.invokeAgent(userMessage); | ||
| await turnContext.sendActivity(response); | ||
| } catch (error) { | ||
| console.error('LLM query error:', error); | ||
| const err = error as any; | ||
| await turnContext.sendActivity(`Error: ${err.message || err}`); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| **What it does**: Handles regular chat messages from users. | ||
|
|
||
| **What happens**: | ||
| 1. **Extract Message**: Gets the user's text from the activity | ||
| 2. **Validate Input**: Checks for non-empty message | ||
| 3. **Create Client**: Gets LangChain client | ||
| 4. **Invoke Agent**: Calls agent with user message | ||
| 5. **Send Response**: Returns AI-generated response to user | ||
| 6. **Error Handling**: Catches problems and returns friendly error messages | ||
| --- | ||
|
|
||
| ## Step 5: Agent Invocation | ||
|
|
||
| Agent invocation is handled in `client.ts`: | ||
|
|
||
| ```typescript | ||
| async invokeAgent(userMessage: string): Promise<string> { | ||
| const result = await this.agent.invoke({ | ||
| messages: [ | ||
| { | ||
| role: "user", | ||
| content: userMessage, | ||
| }, | ||
| ], | ||
| }); | ||
|
|
||
| let agentMessage: any = ''; | ||
|
|
||
| // Extract the content from the LangChain response | ||
| if (result.messages && result.messages.length > 0) { | ||
| const lastMessage = result.messages[result.messages.length - 1]; | ||
| agentMessage = lastMessage.content || "No content in response"; | ||
| } | ||
|
|
||
| // Fallback if result is already a string | ||
| if (typeof result === 'string') { | ||
| agentMessage = result; | ||
| } | ||
|
|
||
| if (!agentMessage) { | ||
| return "Sorry, I couldn't get a response from the agent :("; | ||
| } | ||
|
|
||
| return agentMessage; | ||
| } | ||
| ``` | ||
|
|
||
| **What it does**: Invokes the LangChain agent with the user's message and extracts the response. | ||
|
|
||
| **What happens**: | ||
| 1. **Invoke Agent**: Calls the LangChain agent with the user message | ||
| 2. **Extract Response**: Gets the agent's response from the result | ||
| 3. **Handle Fallbacks**: Returns a friendly message if no response is available | ||
| 4. **Return Result**: Returns the agent's response as a string | ||
| --- | ||
|
|
||
| ## Step 6: Main Entry Point | ||
|
|
||
| The main entry point is in `index.ts`: | ||
|
|
||
| ```typescript | ||
| import { configDotenv } from 'dotenv'; | ||
|
|
||
| configDotenv(); | ||
|
|
||
| import { AuthConfiguration, authorizeJWT, CloudAdapter, Request } from '@microsoft/agents-hosting'; | ||
| import express, { Response } from 'express' | ||
| import { agentApplication } from './agent'; | ||
|
|
||
| const authConfig: AuthConfiguration = {}; | ||
|
|
||
| const server = express() | ||
| server.use(express.json()) | ||
| server.use(authorizeJWT(authConfig)) | ||
|
|
||
| server.post('/api/messages', (req: Request, res: Response) => { | ||
| const adapter = agentApplication.adapter as CloudAdapter; | ||
| adapter.process(req, res, async (context) => { | ||
| await agentApplication.run(context) | ||
| }) | ||
| }) | ||
|
|
||
| const port = process.env.PORT || 3978 | ||
| server.listen(port, async () => { | ||
| console.log(`\nServer listening to port ${port} for appId ${authConfig.clientId} debug ${process.env.DEBUG}`) | ||
| }) | ||
| ``` | ||
|
|
||
| **What it does**: Starts the HTTP server and sets up Bot Framework integration. | ||
|
|
||
| **What happens**: | ||
| 1. **Load Environment**: Reads .env file before importing other modules | ||
| 2. **Create Express Server**: Sets up HTTP server with JSON parsing | ||
| 3. **JWT Authorization**: Adds authentication middleware | ||
| 4. **Bot Framework Endpoint**: Creates /api/messages endpoint for Bot Framework | ||
| 5. **Start Server**: Listens on configured port (default 3978) | ||
|
|
||
| **Why it's useful**: This is the entry point that makes your agent accessible via HTTP! | ||
| --- | ||
|
|
||
| ## Design Patterns and Best Practices | ||
|
|
||
| ### 1. **Factory Pattern** | ||
|
|
||
| Clean client creation through factory function: | ||
|
|
||
| ```typescript | ||
| const client = await getClient(); | ||
| ``` | ||
|
|
||
| ### 2. **Event-Driven Architecture** | ||
|
|
||
| Bot Framework event routing: | ||
|
|
||
| ```typescript | ||
| this.onActivity(ActivityTypes.Message, async (context, state) => { | ||
| await this.handleAgentMessageActivity(context, state); | ||
| }); | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Extension Points | ||
|
|
||
| ### 1. **Adding Tools** | ||
|
|
||
| Extend the agent with LangChain tools: | ||
|
|
||
| ```typescript | ||
| const agent = createAgent({ | ||
| model: model, | ||
| tools: [myCustomTool], | ||
| name: 'My Custom Agent', | ||
| }); | ||
| ``` | ||
|
|
||
| ### 2. **Customizing the Model** | ||
|
|
||
| Change model parameters: | ||
|
|
||
| ```typescript | ||
| const model = new ChatOpenAI({ | ||
| model: "gpt-4o", | ||
| temperature: 0.7, | ||
| }); | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Performance Considerations | ||
|
|
||
| ### 1. **Async Operations** | ||
| - All I/O operations are asynchronous | ||
| - Proper promise handling throughout | ||
|
|
||
| ### 2. **Error Recovery** | ||
| - User-friendly error messages | ||
| - Comprehensive error logging | ||
|
|
||
| --- | ||
|
|
||
| ## Debugging Guide | ||
|
|
||
| ### 1. **Enable Debug Logging** | ||
|
|
||
| Set DEBUG environment variable: | ||
|
|
||
| ```bash | ||
| DEBUG=* | ||
| ``` | ||
|
|
||
| ### 2. **Test Agent Response** | ||
|
|
||
| Check agent invocation: | ||
|
|
||
| ```typescript | ||
| console.log('Agent response:', response); | ||
| ``` | ||
|
|
||
| This architecture provides a solid foundation for building AI agents with LangChain while maintaining flexibility for customization and extension. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| # Sample Agent - Node.js LangChain | ||
|
|
||
| This directory contains a quickstart agent implementation using Node.js and LangChain. | ||
|
|
||
| ## Demonstrates | ||
|
|
||
JesuTerraz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| This sample is used to demonstrate how to build an agent using the Agent365 framework with Node.js and LangChain. The sample includes basic LangChain Agent SDK usage hosted with Agents SDK that is testable on [agentsplayground](https://learn.microsoft.com/en-us/microsoft-365/agents-sdk/test-with-toolkit-project?tabs=windows). | ||
| Please refer to this [quickstart guide](https://review.learn.microsoft.com/en-us/microsoft-agent-365/developer/quickstart-nodejs-langchain?branch=main) on how to extend your agent using Agent365 SDK. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - Node.js 18+ | ||
| - LangChain | ||
| - Agents SDK | ||
JesuTerraz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
JesuTerraz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ## How to run this sample | ||
|
|
||
| 1. **Setup environment variables** | ||
| ```bash | ||
| # Copy the example environment file | ||
| cp .env.template .env | ||
| ``` | ||
|
|
||
| 2. **Install dependencies** | ||
| ```bash | ||
| npm install | ||
| ``` | ||
|
|
||
| 3. **Build the project** | ||
| ```bash | ||
| npm run build | ||
| ``` | ||
|
|
||
| 4. **Start the agent** | ||
| ```bash | ||
| npm start | ||
| ``` | ||
|
|
||
| 5. **Optionally, while testing you can run in dev mode** | ||
| ```bash | ||
| npm run dev | ||
| ``` | ||
|
|
||
| 6. **Start AgentsPlayground to chat with your agent** | ||
| ```bash | ||
| agentsplayground | ||
| ``` | ||
|
|
||
| The agent will start and be ready to receive requests through the configured hosting mechanism. | ||
|
|
||
| ## Documentation | ||
|
|
||
| For detailed information about this sample, please refer to: | ||
|
|
||
| - **[AGENT-CODE-WALKTHROUGH.md](AGENT-CODE-WALKTHROUGH.md)** - Detailed code explanation and architecture walkthrough | ||
|
|
||
| ## 📚 Related Documentation | ||
|
|
||
| - [LangChain Agent SDK Documentation](https://docs.langchain.com/oss/javascript/langchain/overview) | ||
| - [Microsoft 365 Agents SDK](https://github.com/microsoft/Agents-for-js/tree/main) | ||
| - [Model Context Protocol (MCP)](https://github.com/modelcontextprotocol/typescript-sdk/tree/main) | ||
JesuTerraz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ## 🤝 Contributing | ||
|
|
||
| 1. Follow the existing code patterns and structure | ||
| 2. Add comprehensive logging and error handling | ||
| 3. Update documentation for new features | ||
| 4. Test thoroughly with different authentication methods | ||
|
|
||
| ## 📄 License | ||
|
|
||
| This project is licensed under the MIT License - see the [LICENSE](../../../LICENSE.md) file for details. | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.