LangChain Tutorial (Python): deploying to AWS Lambda for intermediate developers

By Cyprian AaronsUpdated 2026-04-21
langchaindeploying-to-aws-lambda-for-intermediate-developerspython

This tutorial shows you how to package a LangChain-based Python app and run it on AWS Lambda behind a simple handler. You’d use this when you want a lightweight LLM endpoint without managing servers, especially for internal tools, chat workflows, or document Q&A.

What You'll Need

  • Python 3.11 locally
  • AWS account with permission to create:
    • Lambda functions
    • IAM roles
    • CloudWatch logs
  • AWS CLI configured locally with aws configure
  • A supported LangChain model provider API key, for example:
    • OPENAI_API_KEY
  • Python packages:
    • langchain
    • langchain-openai
    • boto3 is optional here, but useful for AWS work
  • A deployment zip or container build workflow
  • Basic familiarity with Lambda handlers and environment variables

Step-by-Step

  1. Create a small Lambda-friendly LangChain app.
    Keep the dependency surface tight. For Lambda, avoid pulling in unnecessary integrations and keep the handler stateless.
# app.py
import json
import os

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a concise assistant."),
    ("human", "{question}")
])

llm = ChatOpenAI(
    model="gpt-4o-mini",
    temperature=0,
    api_key=os.environ["OPENAI_API_KEY"],
)

chain = prompt | llm


def lambda_handler(event, context):
    body = json.loads(event.get("body") or "{}")
    question = body.get("question", "What is AWS Lambda?")
    result = chain.invoke({"question": question})
    return {
        "statusCode": 200,
        "headers": {"Content-Type": "application/json"},
        "body": json.dumps({"answer": result.content}),
    }
  1. Pin dependencies for Lambda packaging.
    Lambda is sensitive to version drift, so lock your runtime dependencies. Use a requirements file that matches your code exactly.
# requirements.txt
langchain==0.2.14
langchain-openai==0.1.22
openai==1.40.6
pydantic==2.8.2
tiktoken==0.7.0
  1. Build the deployment package locally.
    Install dependencies into a clean folder and zip them with your handler file. This keeps the artifact compatible with Lambda’s import path.
rm -rf build package lambda.zip
mkdir -p build/package

pip install -r requirements.txt -t build/package

cp app.py build/package/
cd build/package
zip -r ../../lambda.zip .
cd ../..
  1. Create the Lambda function and set environment variables.
    Use Python 3.11, give the function enough memory for model calls, and inject secrets through environment variables or Secrets Manager later.
aws lambda create-function \
  --function-name langchain-tutorial \
  --runtime python3.11 \
  --handler app.lambda_handler \
  --role arn:aws:iam::<YOUR_ACCOUNT_ID>:role/<YOUR_LAMBDA_ROLE> \
  --zip-file fileb://lambda.zip \
  --timeout 30 \
  --memory-size 512 \
  --environment Variables="{OPENAI_API_KEY=your_openai_key}"
  1. Add an API Gateway trigger if you want HTTP access.
    Lambda works fine on its own, but most real use cases need an HTTP endpoint. The simplest path is API Gateway proxy integration.
{
  "body": "{\"question\":\"Explain what this Lambda does.\"}"
}

If you invoke it directly from the console or CLI, the event shape above is enough for this handler.

  1. Improve reliability before production use.
    Add guardrails around input size, timeouts, and error handling so bad requests don’t turn into expensive failures.
# app.py (production-safe version)
import json
import os

from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a concise assistant."),
    ("human", "{question}")
])

llm = ChatOpenAI(
    model="gpt-4o-mini",
    temperature=0,
    api_key=os.environ["OPENAI_API_KEY"],
)

chain = prompt | llm


def lambda_handler(event, context):
    try:
        body = json.loads(event.get("body") or "{}")
        question = str(body.get("question", "")).strip()
        if not question:
            return {"statusCode": 400, "body": json.dumps({"error": "question is required"})}

        result = chain.invoke({"question": question[:2000]})
        return {
            "statusCode": 200,
            "headers": {"Content-Type": "application/json"},
            "body": json.dumps({"answer": result.content}),
        }
    except Exception as e:
        return {"statusCode": 500, "body": json.dumps({"error": str(e)})}

Testing It

Start by invoking the function directly in the AWS console with a simple JSON body containing question. You should get back a JSON response with an answer field containing the model output.

If you used API Gateway, hit the endpoint with curl and verify the response headers and status code are correct.

curl -X POST https:// ձեր-api-id.execute-api.us-east-1.amazonaws.com/prod \
  -H 'Content-Type: application/json' \
  -d '{"question":"What does this deployment do?"}'

Check CloudWatch Logs if something fails. In practice, most issues come from missing environment variables, wrong IAM role permissions, or packaging mistakes where dependencies were not installed into the zip root.

Also confirm cold starts are acceptable for your use case. If latency matters, keep your dependency list small and avoid large transitive installs.

Next Steps

  • Move secrets from plain environment variables to AWS Secrets Manager.
  • Add structured logging and request IDs so you can trace failures in CloudWatch.
  • Swap direct OpenAI calls for a Bedrock-backed LangChain setup if your org standardizes on AWS-native model access.

Keep learning

By Cyprian Aarons, AI Consultant at Topiax.

Want the complete 8-step roadmap?

Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.

Get the Starter Kit

Related Guides