This project records how I built a career counseling chatbot with Claude API. I did not stop at making one API call. I also thought about how to collect student information, structure prompts, and store counseling records.
1. Setting Up the Development Environment
Installing Python
- Install Python 3.8 or later.
- Check Add Python to PATH during installation.
- Confirm the installation with
python --versionin a terminal.
Creating a virtual environment
# Create a virtual environment
python -m venv venv
# Activate on Windows
venv\Scripts\activate
# Activate on macOS/Linux
source venv/bin/activate
Installing libraries
conda install flask
conda install -c conda-forge anthropic
conda install python-dotenv
conda install -c conda-forge flask-sqlalchemy
I managed the dependencies in requirements.txt:
Flask==2.0.1
anthropic==0.3.0
python-dotenv==0.19.0
Flask-SQLAlchemy==2.5.1
2. Configuring Claude API

Creating an API key
- Open the Anthropic website.
- Sign up and log in.
- Open the API section in Console or Dashboard.
- Click Create New API Key.
- Store the generated key somewhere safe.
I created a .env file in the project root:
ANTHROPIC_API_KEY=your_api_key_here
FLASK_ENV=development
FLASK_APP=run.py
3. Setting Up the Project Structure
Directory structure
project/
├── app/
│ ├── __init__.py # Flask application initialization
│ ├── templates/ # HTML templates
│ │ ├── index.html # Main page
│ │ ├── chat.html # Chat interface
│ │ └── base.html # Base template
│ ├── static/ # Static files
│ │ ├── css/ # Stylesheets
│ │ └── js/ # JavaScript
│ └── utils.py # Utility functions
├── config.py # Configuration
├── requirements.txt # Dependencies
└── run.py # Application entry point
Main configuration files
config.py
import os
from dotenv import load_dotenv
load_dotenv()
class Config:
SECRET_KEY = os.urandom(24)
ANTHROPIC_API_KEY = os.getenv('ANTHROPIC_API_KEY')
app/__init__.py
from flask import Flask
from config import Config
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
from app.routes import main
app.register_blueprint(main)
return app
4. Building the Web Interface
Main page

I built the main page quickly with Bootstrap. It was easy to make it responsive, and I included a welcome message and service introduction, a button to start chatting, a usage guide, and recent counseling history for logged-in users.
Chat interface

The chat screen included several features so it felt like an actual counseling session:
- Live message display
- Different styles for user and AI responses
- An input field and send button
- Automatic scrolling through the conversation
- A loading indicator
<!-- Main section of index.html -->
<div class="chat-container">
<div class="chat-messages" id="messageArea">
<!-- Messages are added here dynamically -->
</div>
<div class="input-area">
<input type="text" id="userInput" placeholder="Enter your question..." />
<button onclick="sendMessage()">Send</button>
</div>
</div>
5. Connecting Claude API
API call
# app/utils.py
import anthropic
def get_claude_response(message):
client = anthropic.Client(api_key=os.getenv('ANTHROPIC_API_KEY'))
try:
response = client.messages.create(
model="claude-3-opus-20240229",
max_tokens=1000,
messages=[{
"role": "user",
"content": message
}]
)
return response.content[0].text
except Exception as e:
return f"Error: {str(e)}"
Prompt design
I designed a separate prompt for career counseling. Sending only “give me counseling” produced an answer that was too broad, so I passed student information and counseling criteria together.
def engineer_prompt(user_info, user_message):
system_prompt = """You are an experienced career-counseling AI for high-school students.
Consider these areas during counseling:
1. Academic ability
- Analyze achievement and preferences by subject
- Analyze learning style and study attitude
- Consider activities outside class and self-directed learning
- Consider experience with advanced study in a specific field
2. Aptitude and interests
- Use MBTI and job-fit as one input, not a diagnosis
- Connect hobbies and interests to possible careers
- Consider club and school activities
- Consider volunteer work and civic participation
3. Career exploration and planning
- Provide information about desired job families
- Explain required skills and qualifications
- Introduce related majors and curricula
- Suggest admissions and preparation strategies
4. Skills-development plan
- Suggest study strategies
- Plan relevant certificates and preparation
- Improve foreign-language and computer skills
- Suggest reading and general-education activities
5. Psychological support
- Suggest ways to manage academic stress
- Give advice for career anxiety
- Strengthen confidence and motivation
- Support a positive self-image
6. Future outlook
- Explain industry trends in the field of interest
- Discuss promising future occupations
- Explain how technology may change work
- Connect social change with career adaptability
7. Practical action plan
- Short-term goals (6 months to 1 year)
- Mid-term goals (1 to 3 years)
- Long-term goals (3 to 5 years)
- Concrete actions and a timeline"""
user_context = f"""
# Basic student information
- Name: {user_info['name']}
- Age: {user_info['age']}
- Grade: {user_info['grade']}
- Academic track: {user_info['academic_track']}
# Academic status
- Performance: {user_info['academic_performance']}
- Favorite subject: {user_info['favorite_subject']}
- Disliked subject: {user_info['disliked_subject']}
- Learning style: {user_info.get('learning_style', 'No information')}
# Career exploration
- Interests: {user_info['interests']}
- Career interests: {user_info['career_interests']}
- Desired future job: {user_info['future_job']}
- Role model: {user_info['role_model']}"""
return system_prompt + "\n\n" + user_context + "\n\nStudent message: " + user_message
Response structure
<h2>Overall analysis</h2>
[Professional analysis of the student's traits and situation]
<h2>Career-fit assessment</h2>
[How the desired path matches current abilities]
<h2>Personal development plan</h2>
[Step-by-step goals and actions]
<h2>Recommended materials</h2>
[Personalized learning materials and activities]
What I changed while refining the prompt
- Stronger context: structured student information, connected related facts, and placed information in a useful timeline.
- Better responses: added concrete guidelines, a consistent response structure, and an emphasis on actionable advice.
- More personalization: considered MBTI, learning style, and individual strengths and weaknesses.
- Practicality: added concrete actions, time-based goals, and achievable steps.
6. Connecting the Database
SQLAlchemy model
from app import db
class ChatHistory(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_message = db.Column(db.Text, nullable=False)
ai_response = db.Column(db.Text, nullable=False)
timestamp = db.Column(db.DateTime, default=datetime.utcnow)
Saving and loading conversations
def save_chat(user_message, ai_response):
chat = ChatHistory(
user_message=user_message,
ai_response=ai_response
)
db.session.add(chat)
db.session.commit()
7. Security and Error Handling
API-key security
- Use environment variables.
- Add
.envto.gitignore. - Keep production security settings separate.
Error handling
@app.errorhandler(500)
def internal_error(error):
return jsonify({
'error': 'Internal server error',
'message': str(error)
}), 500
8. Preparing for Deployment
Production settings
# config.py
class ProductionConfig(Config):
DEBUG = False
SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URL')
Running the server
gunicorn run:app
Closing Thoughts
Building this project taught me that simply “adding a chatbot” requires more structure than I expected. API-key management, prompt design, conversation storage, and error handling all have to be handled before the result is actually usable.
The areas I practiced were Flask, API integration and asynchronous handling, database design, frontend interfaces, and security and error handling.
If I improved it further, I would add:
- User authentication
- Counseling-history analysis and reports
- Multilingual support
- A voice interface
- A mobile-app version
The full source is available on GitHub. There are still many things I would clean up, but connecting Claude API to a real service was valuable practice.